Compare commits

...

76 commits

Author SHA1 Message Date
Dane Springmeyer
025b04fe2b fix #2287 in 2.0.x branch 2014-07-28 17:27:05 -07:00
Dane Springmeyer
4acda0a752 fix compile of json feature_collection grammar when building against boost >= 1.52 - refs #1658 and #1716 2013-02-10 16:59:31 -08:00
Dane Springmeyer
7cf334852d add to changelog for 2.0.3 2012-12-05 20:06:36 -08:00
Dane Springmeyer
e61644b930 boost system linking in python too 2012-12-05 19:57:55 -08:00
Dane Springmeyer
fd27717253 finish backport to 2.0.x of fix for #1464 2012-12-05 19:57:29 -08:00
Dane Springmeyer
1aa28fb966 add 'ignore-placement' to list of expected parameters for markers_symbolizer to avoid spurious warning during load_map when the parameter is used 2012-11-27 13:08:55 -08:00
Artem Pavlenko
ca43cc3f40 Merge pull request #1466 from strk/2.0.x-literals
2.0.x literals
2012-09-05 02:41:16 -07:00
Sandro Santilli
170e23440f Add support for literal types in PostGIS queries. Closes #1464. 2012-09-04 18:20:15 +02:00
Dane Springmeyer
ed734df467 now working on mapnik v2.0.3-pre 2012-08-03 18:06:02 -07:00
Dane Springmeyer
3b831a485d update CHANGELOG 2012-08-03 18:00:26 -07:00
Dane Springmeyer
adb2ec7414 setting up for mapnik v2.0.2 release 2012-08-03 17:59:20 -07:00
Dane Springmeyer
7e36b13dce update CHANGELOG for 2.0.2 release 2012-08-03 17:50:00 -07:00
Dane Springmeyer
daeecb39e0 handle empty geometries from postgis and add postgis tests - refs #1333 2012-08-03 17:42:10 -07:00
Dane Springmeyer
fa23cda22f avoid unused variable warnings 2012-08-03 17:27:33 -07:00
artemp
cc3cd5f63f + fixed naming (as per SVG) 2012-08-01 13:50:50 -07:00
Dane Springmeyer
9b251e16f7 fix initialization order with markers_symbolizer to avoid compiler warning 2012-07-05 14:52:15 -07:00
Dane Springmeyer
8dea5a5fe2 future proof linking of postgis plugin against boost 1.50 2012-07-05 14:25:58 -07:00
Dane Springmeyer
718d3a4e66 switch grid member intialization order to avoid compiler warning 2012-07-05 14:25:32 -07:00
Dane Springmeyer
49483fa2dd ensure valid string concatenation 2012-07-05 14:19:34 -07:00
Dane Springmeyer
d139e491c2 add missing throw 2012-07-05 13:35:26 -07:00
Dane Springmeyer
f878989b2e avoid unused variable warning 2012-07-05 13:35:08 -07:00
Dane Springmeyer
6a6a48bc6c consistenly pass the unbuffered map dimensions to the placement_finder, ensuring that avoid-edges and minimum-padding are respected across all renderers, if set - closes #1242 2012-07-05 12:03:43 -07:00
Dane Springmeyer
7a7ab494f4 use ST_AsBinary for postgis_datasource::features_at_point - closes #1252 2012-07-04 16:35:06 -07:00
Dane Springmeyer
dc813167c7 initialize boolean grid.painted 2012-07-04 14:15:44 -07:00
Dane Springmeyer
ff271853ce partially rollback b93c760b33 - meaning that radii will continue (as in Mapnik 2.0.0) to be assumed for marker width/height in the Mapnik 2.0.x series (>= 2.0.2) - closes #1163, refs #1134 2012-07-04 11:33:58 -07:00
Dane Springmeyer
57a3836c50 avoid throwing if Mapnik 2.1 style <Parameters> is encountered in XML 2012-07-04 11:19:51 -07:00
Dane Springmeyer
3b44a88c44 update changlog after 47e5b3c 2012-07-03 12:17:28 -07:00
artemp
47e5b3c95e + use ST_xxx 2012-07-03 12:16:02 -07:00
Dane Springmeyer
51bf0ef2a5 scons: port minor build fixes from master to make building os x binaries (against static icu and libpq) easier 2012-06-15 15:00:51 -04:00
Dane Springmeyer
c8848c8a9b only mark deprecated api names for removal at major versions to ensure we are semver compatible - thanks @migurski - closes #1129 2012-06-06 17:32:36 -07:00
Dane Springmeyer
2b5ad5bd7e update changelog after #1171 and #1221 2012-05-18 13:48:23 -07:00
Dane Springmeyer
92dd30556a python: fix leaky Py_None return by calling Py_INCREF(Py_None) before returning - closes #1221 2012-05-18 13:28:58 -07:00
Dane Springmeyer
7fe677dd41 avoid trying to determine relative path from python module to plugins as this can make flexible packaging harder - closes #1171 2012-05-03 21:49:09 -04:00
Dane Springmeyer
19b51fd43b bump api fallback version 2012-04-11 08:19:27 -07:00
Dane Springmeyer
c1ed1da9e2 update changelog after #1173 2012-04-11 08:18:39 -07:00
Dane Springmeyer
0370913bfc fix memory leak of pj_ctx if a projection cannot be initialized 2012-04-11 08:14:37 -07:00
Dane Springmeyer
56d8f7a3f9 now working on mapnik 2.0.2-pre 2012-04-09 14:29:01 -07:00
Dane Springmeyer
57347e9106 update CHANGELOG 2012-04-09 14:22:48 -07:00
Dane Springmeyer
5cd3cb2efd setting up for mapnik 2.0.1 release 2012-04-09 14:21:48 -07:00
Dane Springmeyer
862bd54799 shuffle CHANGELOG 2012-04-09 14:15:53 -07:00
Dane Springmeyer
1f49c52be4 add hello world plugin to gitignores 2012-04-09 14:12:17 -07:00
Dane Springmeyer
bd8446d875 forward compatibility with mapnik >= 2.1.x header name 2012-04-09 14:07:18 -07:00
Dane Springmeyer
af6cd78ab9 embed version in the epydoc output 2012-04-09 13:52:54 -07:00
Dane Springmeyer
b93c760b33 backport markers_symbolizer fixes from master to 2.0.x - closes #1163 2012-04-04 11:19:40 -07:00
Dane Springmeyer
c9a610df92 add missing set_color_to_alpha impl - TODO - add advanced algo that supports tolerance - refs #1018 2012-04-04 10:22:02 -07:00
Dane Springmeyer
50abe356d8 remove #1072 from changelog as it was ultimately reverted from 2.0.x branch 2012-03-24 08:02:20 -07:00
Dane Springmeyer
0be7d66549 Revert "avoid mutex locks on pj_transform for proj 4.7 and above - closes #1072"
This reverts commit 150c9f819a.
2012-03-24 08:01:13 -07:00
Dane Springmeyer
19f43c9d2f add 0f5ab18ed backport to changelog 2012-03-15 19:10:04 -07:00
Artem Pavlenko
49f0df0f7f avoid creating default initialised values if key doesn't exist 2012-03-15 19:01:17 -07:00
Dane Springmeyer
896bcbd211 since mapnik::layer is public api, add forward compatibility with >= mapnik 2.1.x 2012-03-15 12:42:02 -07:00
Dane Springmeyer
a6891f2459 Merge branch '2.0.x' of github.com:mapnik/mapnik into 2.0.x 2012-03-14 22:10:06 -07:00
Dane Springmeyer
e66d724841 remove id 2012-03-14 22:09:40 -07:00
Dane Springmeyer
cacc90962c add deprecated python module alias for backward compatibility 2012-03-15 02:19:48 +00:00
Dane Springmeyer
91ad01b11b properly format abi versions in a few more placesa 2012-03-15 02:04:10 +00:00
Dane Springmeyer
8229b22ed7 fix linux soname formatting 2012-03-14 18:31:54 -07:00
Dane Springmeyer
1912362b46 make available MAPNIK_VERSION_STRING in c++ header (not just in python) and add MAPNIK_VERSION_IS_RELEASE define that indicates if the code is released 2012-03-14 17:26:50 -07:00
Dane Springmeyer
9ddef6463f backport 'switch naming back from libmapnik2 -> libmapnik (also python)' and remove svn traces (refs #941) 2012-03-14 15:44:48 -07:00
Dane Springmeyer
e7f62675a9 remove ogcserver - now at https://github.com/mapnik/OGCServer 2012-03-14 15:29:49 -07:00
Dane Springmeyer
34ddc65e30 backport to 2.0.x series the sqlite3_open_v2 usage from master - refs #854 2012-03-14 15:08:39 -07:00
Dane Springmeyer
7a10befa11 update CHANGELOG 2012-03-14 14:40:41 -07:00
Dane Springmeyer
4292cf1687 add emacs temporaries to gitignores 2012-03-14 14:40:06 -07:00
Dane Springmeyer
b0c6378eb8 postgis: remove last usage of deprecated functions - fully supporting postgis 2.0 - closes #1083 2012-02-23 16:15:34 -08:00
Dane Springmeyer
21af038fd3 support as low as geos v3.1.0 - closes #1031 2012-02-23 16:14:03 -08:00
Dane Springmeyer
3a086b8dfc sync changelog 2012-02-23 16:11:41 -08:00
Dane Springmeyer
150c9f819a avoid mutex locks on pj_transform for proj 4.7 and above - closes #1072 2012-02-23 16:09:56 -08:00
Matt Amos
90fccfe710 Still need to increment pos counter in shapeindex even when the geometry is null, otherwise reads are possible beyond the end of file. 2012-02-23 16:08:54 -08:00
Dane Springmeyer
ee8a150e38 backport hextree sorting fix to 2.0.x series - refs #1087 2012-02-23 16:01:09 -08:00
Dane Springmeyer
53e171c1f1 yet another -fpermissive - refs #1082, #950 and #1001 2012-02-15 10:24:28 -08:00
Dane Springmeyer
01d6567007 add permissive flag to ogr and shape plugins to work around boost interprocess compile bug - closes #1082 - refs #950 and #1001 2012-02-15 10:24:16 -08:00
Dane Springmeyer
496b393623 backport to 2.0.2 fix for ubuntu compile error with boost 1.42 - refs #950 and #1001 2012-01-17 00:23:41 -05:00
kunitoki
babe1b6fd0 - fix mapnik-config --version
- closes #903
2011-11-29 12:15:53 -08:00
Dane Springmeyer
58c29c052b remove unintended plugin line that snuck in from master merge 2011-11-29 12:14:33 -08:00
Dane Springmeyer
c4edd2bd59 backport postgis 2.x fix to mapnik 2.0.x series branch - refs #956 2011-11-20 14:43:22 -08:00
Robert Coup
5c76218070 [fixes #904] Python2.5 compatibility. 2011-10-31 10:54:10 +13:00
Robert Coup
7eef4af143 Do a proper check for BOOST_PYTHON_LIB in scons, and change it to be only the library name. re: mapnik-packaging:#3 2011-10-21 16:40:45 -07:00
Dane Springmeyer
86a1d9626b update changelog - #908 2011-10-17 14:13:43 -07:00
115 changed files with 1818 additions and 2769 deletions

3
.gitignore vendored
View file

@ -4,7 +4,10 @@
*.so
*.a
*.dylib
*.cpp~
*.hpp~
plugins/input/*.input
plugins/input/templates/hello.input
demo/c++/rundemo
bindings/python/mapnik/paths.py
config.cache

View file

@ -10,12 +10,76 @@ Developers: Please commit along with changes.
For a complete change history, see the SVN log.
Future
Mapnik 2.1.0
- Fixed linking to recent boost versions
- Added support for literal types in PostGIS Plugin (#1464)
Mapnik 2.0.2
------------
Released Aug 3, 2012
(Packaged from adb2ec741)
- Fixed handling of empty WKB geometries (#1334)
- Fixed naming of `stroke-dashoffset` in save_map (cc3cd5f63f28)
- Fixed support for boost 1.50 (8dea5a5fe239233)
- Fixed TextSymbolizer placement in Cairo backend so it respects avoid-edges and minimum-padding across all renderers (#1242)
- Fixed ShieldSymbolizer placement so it respects avoid-edges and minimum-padding across all renderers (#1242)
- Rolled back change made in 2.0.1 to marker width/height meaning that Mapnik > 2.0.2 will stick to assuming width/heigh are radii for back compatibility with 2.0.0. The reverted change is seen below as "Fix Markers rendering so that ellipse height/width units are pixels (previously were unintentionally radii)". Issue tracking this is #1163
- XML: Fixed to avoid throwing if a `<Parameters>` element is encountered (which is supported in >= 2.1.x)
- Support for PostGIS 2.0 in the pgsql2sqlite command (e69c44e/47e5b3c)
- Fixed reference counting of Py_None when returning null attributes from Postgres during UTFGrid encoding, which could cause a Fatal Python error: deallocating None (#1221)
- Fixed possible breakage registering plugins via python if a custom PREFIX or DESTDIR was used (e.g. macports/homebrew) (#1171)
- Fixed memory leak in the case of proj >= 4.8 and a projection initialization error (#1173)
Mapnik 2.0.1
------------
(Packaged from 5cd3cb2efdaf7e9990a57e8e00b652a81aaa39ae)
- Support for PostGIS 2.0 (#956,#1083)
- Switched back to "libmapnik" and "import mapnik" rather than "mapnik2" (mapnik2 will still work from python) (#941)
- Restored Python 2.5 compatibility (#904)
- Fixed `mapnik-config --version` (#903)
- 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)
- Removed svn_revision info from mapnik-config and python bindings as git is now used
- Removed OGCServer from core - now at https://github.com/mapnik/OGCServer (e7f6267)
- Fixed SQLite open stability across platforms/versions (#854)
- Workaround for boost interprocess compile error with recent gcc versions (#950,#1001,#1082)
- Fix possible memory corruption when using hextree mode for png color reduction (#1087)
- Fixed bug in shield line placement when dx/dy are used to shift the label relative to the placement point (Matt Amos) (#908)
- Fix to avoid modifying a feature if an attribute is requested that does not exist (0f5ab18ed)
- Fixed ability to save to jpeg format from python (7387afd9) (#896)
Mapnik 2.0.0
@ -225,8 +289,6 @@ Mapnik 0.7.0 Release
- Python: Fixed potential crash if pycairo support is enabled but python-cairo module is missing (#392)
- Python: Added 'mapnik.mapnik_svn_revision()' function to svn revision of Mapnik was compiled at.
- Python: Added 'mapnik.has_pycairo()' function to test for pycairo support (r1278) (#284)
- Python: Added 'mapnik.register_plugins()' and 'mapnik.register_fonts()' functions (r1256)

View file

@ -16,7 +16,6 @@
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# $Id$
import os
@ -53,17 +52,17 @@ DEFAULT_LINK_PRIORITY = ['internal','other','frameworks','user','system']
pretty_dep_names = {
'ociei':'Oracle database library | configure with OCCI_LIBS & OCCI_INCLUDES | more info: http://trac.mapnik.org/wiki/OCCI',
'gdal':'GDAL C++ library | configured using gdal-config program | try setting GDAL_CONFIG SCons option | more info: http://trac.mapnik.org/wiki/GDAL',
'ogr':'OGR-enabled GDAL C++ Library | configured using gdal-config program | try setting GDAL_CONFIG SCons option | more info: http://trac.mapnik.org/wiki/OGR',
'geos_c':'GEOS Simple Geometry Specification C Library | configured with GEOS_LIB & GEOS_INCLUDE | more info: http://trac.mapnik.org/wiki/GEOS',
'ociei':'Oracle database library | configure with OCCI_LIBS & OCCI_INCLUDES | more info: https://github.com/mapnik/mapnik/wiki/OCCI',
'gdal':'GDAL C++ library | configured using gdal-config program | try setting GDAL_CONFIG SCons option | more info: https://github.com/mapnik/mapnik/wiki/GDAL',
'ogr':'OGR-enabled GDAL C++ Library | configured using gdal-config program | try setting GDAL_CONFIG SCons option | more info: https://github.com/mapnik/mapnik/wiki/OGR',
'geos_c':'GEOS Simple Geometry Specification C Library | configured with GEOS_LIB & GEOS_INCLUDE | more info: https://github.com/mapnik/mapnik/wiki/GEOS',
'cairo':'Cairo C library | configured using pkg-config | try setting PKG_CONFIG_PATH SCons option',
'cairomm':'Cairomm C++ bindings to Cairo library | configured using pkg-config | try setting PKG_CONFIG_PATH SCons option',
'cairomm-version':'Cairomm version is too old (so cairo renderer will not be built), you need at least %s' % CAIROMM_MIN_VERSION,
'pycairo':'Python bindings to Cairo library | configured using pkg-config | try setting PKG_CONFIG_PATH SCons option',
'proj':'Proj.4 C Projections library | configure with PROJ_LIBS & PROJ_INCLUDES | more info: http://trac.osgeo.org/proj/',
'pg':'Postgres C Library requiered for PostGIS plugin | configure with pg_config program | more info: http://trac.mapnik.org/wiki/PostGIS',
'sqlite3':'SQLite3 C Library | configure with SQLITE_LIBS & SQLITE_INCLUDES | more info: http://trac.mapnik.org/wiki/SQLite',
'pg':'Postgres C Library requiered for PostGIS plugin | configure with pg_config program | more info: https://github.com/mapnik/mapnik/wiki/PostGIS',
'sqlite3':'SQLite3 C Library | configure with SQLITE_LIBS & SQLITE_INCLUDES | more info: https://github.com/mapnik/mapnik/wiki/SQLite',
'jpeg':'JPEG C library | configure with JPEG_LIBS & JPEG_INCLUDES',
'tiff':'TIFF C library | configure with TIFF_LIBS & TIFF_INCLUDES',
'png':'PNG C library | configure with PNG_LIBS & PNG_INCLUDES',
@ -77,8 +76,8 @@ pretty_dep_names = {
'gdal-config':'gdal-config program | try setting GDAL_CONFIG SCons option',
'geos-config':'geos-config program | try setting GEOS_CONFIG SCons option',
'freetype-config':'freetype-config program | try setting FREETYPE_CONFIG SCons option',
'osm':'more info: http://trac.mapnik.org/wiki/OsmPlugin',
'curl':'libcurl is required for the "osm" plugin - more info: http://trac.mapnik.org/wiki/OsmPlugin',
'osm':'more info: https://github.com/mapnik/mapnik/wiki/OsmPlugin',
'curl':'libcurl is required for the "osm" plugin - more info: https://github.com/mapnik/mapnik/wiki/OsmPlugin',
'boost_regex_icu':'libboost_regex built with optional ICU unicode support is needed for unicode regex support in mapnik.',
'sqlite_rtree':'The SQLite plugin requires libsqlite3 built with RTREE support (-DSQLITE_ENABLE_RTREE=1)',
'pgsql2sqlite_rtree':'The pgsql2sqlite program requires libsqlite3 built with RTREE support (-DSQLITE_ENABLE_RTREE=1)'
@ -102,7 +101,6 @@ PLUGINS = { # plugins with external dependencies
# plugins without external dependencies requiring CheckLibWithHeader...
'shape': {'default':True,'path':None,'inc':None,'lib':None,'lang':'C++'},
'csv': {'default':False,'path':None,'inc':None,'lib':None,'lang':'C++'},
'raster': {'default':True,'path':None,'inc':None,'lib':None,'lang':'C++'},
'kismet': {'default':False,'path':None,'inc':None,'lib':None,'lang':'C++'},
}
@ -278,7 +276,7 @@ def pretty_dep(dep):
if pretty:
return '%s (%s)' % (dep,pretty)
elif 'boost' in dep:
return '%s (%s)' % (dep,'more info see: http://trac.mapnik.org/wiki/MapnikInstallation & http://www.boost.org')
return '%s (%s)' % (dep,'more info see: https://github.com/mapnik/mapnik/wiki/MapnikInstallation & http://www.boost.org')
return dep
@ -329,7 +327,7 @@ opts.AddVariables(
('BOOST_TOOLKIT','Specify boost toolkit, e.g., gcc41.','',False),
('BOOST_ABI', 'Specify boost ABI, e.g., d.','',False),
('BOOST_VERSION','Specify boost version, e.g., 1_35.','',False),
('BOOST_PYTHON_LIB','Specify library name or full path to boost_python lib (e.g. "boost_python-py26" or "/usr/lib/libboost_python.dylib")',''),
('BOOST_PYTHON_LIB','Specify library name to specific Boost Python lib (e.g. "boost_python-py26")',''),
# Variables for required dependencies
('FREETYPE_CONFIG', 'The path to the freetype-config executable.', 'freetype-config'),
@ -375,7 +373,7 @@ opts.AddVariables(
# Other variables
BoolVariable('SHAPE_MEMORY_MAPPED_FILE', 'Utilize memory-mapped files in Shapefile Plugin (higher memory usage, better performance)', 'True'),
('SYSTEM_FONTS','Provide location for python bindings to register fonts (if given aborts installation of bundled DejaVu fonts)',''),
('LIB_DIR_NAME','Name to use for the subfolder beside libmapnik where fonts and plugins are installed','mapnik2'),
('LIB_DIR_NAME','Name to use for the subfolder beside libmapnik where fonts and plugins are installed','mapnik'),
PathVariable('PYTHON','Full path to Python executable used to build bindings', sys.executable),
BoolVariable('FRAMEWORK_PYTHON', 'Link against Framework Python on Mac OS X', 'True'),
BoolVariable('PYTHON_DYNAMIC_LOOKUP', 'On OSX, do not directly link python lib, but rather dynamically lookup symbols', 'True'),
@ -426,7 +424,6 @@ pickle_store = [# Scons internal variables
'PYTHON_SYS_PREFIX',
'COLOR_PRINT',
'HAS_BOOST_SYSTEM',
'SVN_REVISION',
'HAS_CAIRO',
'HAS_PYCAIRO',
'HAS_LIBXML2',
@ -451,6 +448,7 @@ pickle_store = [# Scons internal variables
'CAIROMM_LIBPATHS',
'CAIROMM_LINKFLAGS',
'CAIROMM_CPPPATHS',
'BOOST_LIB_VERSION_FROM_HEADER'
]
# Add all other user configurable options to pickle pickle_store
@ -525,11 +523,6 @@ if sys.platform == "win32":
color_print(4,'\nWelcome to Mapnik...\n')
color_print(1,'*'*45)
color_print(1,'You are compiling Mapnik trunk (aka Mapnik2)')
color_print(1,'See important details at:\nhttp://trac.mapnik.org/wiki/Mapnik2')
color_print(1,('*'*45)+'\n')
#### Custom Configure Checks ###
@ -799,7 +792,7 @@ def GetMapnikLibVersion(context):
int main()
{
std::cout << MAPNIK_VERSION << std::endl;
std::cout << MAPNIK_VERSION_STRING << std::endl;
return 0;
}
@ -809,11 +802,7 @@ int main()
context.Result(ret[0])
if not ret[1]:
return []
version = int(ret[1].strip())
patch_level = version % 100
minor_version = version / 100 % 1000
major_version = version / 100000
return [major_version,minor_version,patch_level]
return ret[1].strip()
def icu_at_least_four_two(context):
ret = context.TryRun("""
@ -845,6 +834,9 @@ int main()
return False
def boost_regex_has_icu(context):
if env['RUNTIME_LINK'] == 'static':
context.env.Append(LIBS='icui18n')
context.env.Append(LIBS='icudata')
ret = context.TryRun("""
#include <boost/regex/icu.hpp>
@ -969,7 +961,6 @@ if not preconfigured:
env['CAIROMM_CPPPATHS'] = []
env['HAS_PYCAIRO'] = False
env['HAS_LIBXML2'] = False
env['SVN_REVISION'] = None
env['LIBMAPNIK_LIBS'] = []
env['LIBMAPNIK_CPPATHS'] = []
env['LIBMAPNIK_CXXFLAGS'] = []
@ -1010,9 +1001,9 @@ if not preconfigured:
env['MAPNIK_FONTS_DEST'] = os.path.join(env['MAPNIK_LIB_DIR_DEST'],'fonts')
if env['LINKING'] == 'static':
env['MAPNIK_LIB_NAME'] = '${LIBPREFIX}mapnik2${LIBSUFFIX}'
env['MAPNIK_LIB_NAME'] = '${LIBPREFIX}mapnik${LIBSUFFIX}'
else:
env['MAPNIK_LIB_NAME'] = '${SHLIBPREFIX}mapnik2${SHLIBSUFFIX}'
env['MAPNIK_LIB_NAME'] = '${SHLIBPREFIX}mapnik${SHLIBSUFFIX}'
if env['PKG_CONFIG_PATH']:
env['ENV']['PKG_CONFIG_PATH'] = os.path.realpath(env['PKG_CONFIG_PATH'])
@ -1111,14 +1102,14 @@ if not preconfigured:
if env['PRIORITIZE_LINKING']:
conf.prioritize_paths(silent=False)
for libinfo in LIBSHEADERS:
if not conf.CheckLibWithHeader(libinfo[0], libinfo[1], libinfo[3]):
if libinfo[2]:
color_print(1,'Could not find required header or shared library for %s' % libinfo[0])
env['MISSING_DEPS'].append(libinfo[0])
for libname, headers, required, lang in LIBSHEADERS:
if not conf.CheckLibWithHeader(libname, headers, lang):
if required:
color_print(1, 'Could not find required header or shared library for %s' % libname)
env['MISSING_DEPS'].append(libname)
else:
color_print(4,'Could not find optional header or shared library for %s' % libinfo[0])
env['SKIPPED_DEPS'].append(libinfo[0])
color_print(4, 'Could not find optional header or shared library for %s' % libname)
env['SKIPPED_DEPS'].append(libname)
if env['ICU_LIB_NAME'] not in env['MISSING_DEPS']:
if not conf.icu_at_least_four_two():
@ -1134,9 +1125,9 @@ if not preconfigured:
# boost system is used in boost 1.35 and greater
env['HAS_BOOST_SYSTEM'] = False
boost_lib_version_from_header = conf.GetBoostLibVersion()
if boost_lib_version_from_header:
boost_version_from_header = int(boost_lib_version_from_header.split('_')[1])
env['BOOST_LIB_VERSION_FROM_HEADER'] = conf.GetBoostLibVersion()
if env['BOOST_LIB_VERSION_FROM_HEADER']:
boost_version_from_header = int(env['BOOST_LIB_VERSION_FROM_HEADER'].split('_')[1])
if boost_version_from_header >= 35:
env['HAS_BOOST_SYSTEM'] = True
@ -1169,7 +1160,7 @@ if not preconfigured:
if not env['BOOST_VERSION']:
env['MISSING_DEPS'].append('boost version >=%s' % BOOST_MIN_VERSION)
else:
color_print(4,'Found boost lib version... %s' % boost_lib_version_from_header )
color_print(4,'Found boost lib version... %s' % env['BOOST_LIB_VERSION_FROM_HEADER'] )
for count, libinfo in enumerate(BOOST_LIBSHEADERS):
if not conf.CheckLibWithHeader('boost_%s%s' % (libinfo[0],env['BOOST_APPEND']), libinfo[1], 'C++'):
@ -1329,7 +1320,7 @@ if not preconfigured:
if not conf.CheckHeader(header='boost/python/detail/config.hpp',language='C++'):
color_print(1,'Could not find required header files for boost python')
env['MISSING_DEPS'].append('boost python')
if env['CAIRO']:
if conf.CheckPKGConfig('0.15.0') and conf.CheckPKG('pycairo'):
env['HAS_PYCAIRO'] = True
@ -1353,7 +1344,7 @@ if not preconfigured:
color_print(4," $ sudo python scons/scons.py install")
color_print(4,"\nTo view available path variables:\n $ python scons/scons.py --help or -h")
color_print(4,'\nTo view overall SCons help options:\n $ python scons/scons.py --help-options or -H\n')
color_print(4,'More info: http://trac.mapnik.org/wiki/MapnikInstallation')
color_print(4,'More info: https://github.com/mapnik/mapnik/wiki/MapnikInstallation')
if not HELP_REQUESTED:
Exit(1)
else:
@ -1379,27 +1370,19 @@ 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,0]
abi_fallback = "2.0.3"
if not abi:
color_print(1,'Problem encountered parsing mapnik version, falling back to %s' % abi_fallback)
env['ABI_VERSION'] = abi_fallback
else:
env['ABI_VERSION'] = abi
env['MAPNIK_VERSION_STRING'] = '.'.join(['%d' % i for i in env['ABI_VERSION']])
abi = abi_fallback
env['ABI_VERSION'] = abi.replace('-pre','').split('.')
env['MAPNIK_VERSION_STRING'] = abi
# Common C++ flags.
if env['THREADING'] == 'multi':
common_cxx_flags = '-D%s -DBOOST_SPIRIT_THREADSAFE -DMAPNIK_THREADSAFE ' % env['PLATFORM'].upper()
else :
common_cxx_flags = '-D%s ' % env['PLATFORM'].upper()
svn_version = call('svnversion')
if not svn_version == 'exported':
pattern = r'(\d+)(.*)'
try:
env['SVN_REVISION'] = re.match(pattern,svn_version).groups()[0]
except: pass
# Mac OSX (Darwin) special settings
if env['PLATFORM'] == 'Darwin':
@ -1500,14 +1483,23 @@ if not preconfigured:
if not conf.CheckHeader(header='Python.h',language='C'):
color_print(1,'Could not find required header files for the Python language (version %s)' % env['PYTHON_VERSION'])
env.Replace(**backup)
env['MISSING_DEPS'].append('python %s development headers' % env['PYTHON_VERSION'])
Exit(1)
else:
env.Replace(**backup)
if (int(majver), int(minver)) < (2, 2):
color_print(1,"Python version 2.2 or greater required")
Exit(1)
if env['BOOST_PYTHON_LIB']:
env.Append(LIBS='python%s' % env['PYTHON_VERSION'])
if not conf.CheckLibWithHeader(libs=[env['BOOST_PYTHON_LIB']], header='boost/python/detail/config.hpp', language='C++'):
color_print(1, 'Could not find library %s for boost python' % env['BOOST_PYTHON_LIB'])
env.Replace(**backup)
Exit(1)
else:
env.Replace(**backup)
color_print(4,'Bindings Python version... %s' % env['PYTHON_VERSION'])
color_print(4,'Python %s prefix... %s' % (env['PYTHON_VERSION'], env['PYTHON_SYS_PREFIX']))
color_print(4,'Python bindings will install in... %s' % os.path.normpath(env['PYTHON_INSTALL_LOCATION']))
@ -1673,7 +1665,7 @@ if not HELP_REQUESTED:
# Install the python speed testing scripts if python bindings will be available
SConscript('utils/performance/build.py')
# Install the mapnik2 upgrade script
# Install the mapnik upgrade script
SConscript('utils/upgrade_map_xml/build.py')
# Configure fonts and if requested install the bundled DejaVu fonts

View file

@ -40,32 +40,32 @@ def is_py3():
prefix = env['PREFIX']
target_path = os.path.normpath(env['PYTHON_INSTALL_LOCATION'] + os.path.sep + 'mapnik2')
target_path = os.path.normpath(env['PYTHON_INSTALL_LOCATION'] + os.path.sep + 'mapnik')
target_path_deprecated = os.path.normpath(env['PYTHON_INSTALL_LOCATION'] + os.path.sep + 'mapnik2')
libraries = ['mapnik2','png']
libraries = ['mapnik']
if env['JPEG']:
libraries.append('jpeg')
if env['HAS_BOOST_SYSTEM']:
libraries.append('boost_system%s' % env['BOOST_APPEND'])
if env['BOOST_PYTHON_LIB']:
if os.path.sep in env['BOOST_PYTHON_LIB']:
pylib_dir = os.path.dirname(env['BOOST_PYTHON_LIB'])
env.Prepend(LIBPATH = pylib_dir)
pylib_name = os.path.splitext(os.path.basename(env['BOOST_PYTHON_LIB']))[0].replace('lib','',1)
libraries.append(pylib_name)
else:
libraries.append(env['BOOST_PYTHON_LIB'].replace('lib','',1))
libraries.append(env['BOOST_PYTHON_LIB'])
else:
if is_py3():
libraries.append('boost_python3%s' % env['BOOST_APPEND'])
else:
libraries.append('boost_python%s' % env['BOOST_APPEND'])
# TODO - do solaris/fedora need direct linking too?
if env['PLATFORM'] == 'Darwin':
libraries.append(env['ICU_LIB_NAME'])
libraries.append('boost_regex%s' % env['BOOST_APPEND'])
if env['THREADING'] == 'multi':
libraries.append('boost_thread%s' % env['BOOST_APPEND'])
if not env['PYTHON_DYNAMIC_LOOKUP']:
libraries.append('png')
if env['JPEG']:
libraries.append('jpeg')
libraries.append(env['ICU_LIB_NAME'])
libraries.append('boost_regex%s' % env['BOOST_APPEND'])
if env['THREADING'] == 'multi':
libraries.append('boost_thread%s' % env['BOOST_APPEND'])
##### Python linking on OS X is tricky ###
# Confounding problems are:
@ -111,6 +111,7 @@ if env['PLATFORM'] == 'Darwin':
else:
# TODO - do we need to pass -L/?
python_link_flag = '-lpython%s' % env['PYTHON_VERSION']
elif env['PLATFORM'] == 'SunOS':
# make sure to explicitly link mapnik.so against
# libmapnik in its installed location
@ -127,21 +128,24 @@ else:
paths = '''
"""Configuration paths of Mapnik fonts and input plugins (auto-generated by SCons)."""
import os
from os.path import normpath,join,dirname
mapniklibpath = '%s'
mapniklibpath = normpath(join(dirname(__file__),mapniklibpath))
'''
paths += "inputpluginspath = os.path.normpath(mapniklibpath + '/input')\n"
paths += "inputpluginspath = join(mapniklibpath,'input')\n"
if env['SYSTEM_FONTS']:
paths += "fontscollectionpath = os.path.normpath('%s')" % env['SYSTEM_FONTS']
paths += "fontscollectionpath = normpath('%s')\n" % env['SYSTEM_FONTS']
else:
paths += "fontscollectionpath = os.path.normpath(mapniklibpath + '/fonts')"
paths += "fontscollectionpath = join(mapniklibpath,'fonts')\n"
paths += "__all__ = [mapniklibpath,inputpluginspath,fontscollectionpath]\n"
if not os.path.exists('mapnik'):
os.mkdir('mapnik')
file('mapnik/paths.py','w').write(paths % (env['MAPNIK_LIB_DIR']))
# force open perms temporarily so that `sudo scons install`
@ -157,7 +161,10 @@ if 'install' in COMMAND_LINE_TARGETS:
init_files.remove('mapnik/paths.py')
init_module = env.Install(target_path, init_files)
env.Alias(target='install', source=init_module)
# install mapnik2 module which redirects to mapnik and issues DeprecatedWarning
init_mapnik2 = env.Install(target_path_deprecated, 'mapnik2/__init__.py')
env.Alias(target='install', source=init_mapnik2)
# fix perms and install the custom generated 'paths.py'
if 'install' in COMMAND_LINE_TARGETS:
targetp = os.path.join(target_path,'paths.py')
@ -169,18 +176,11 @@ if 'install' in COMMAND_LINE_TARGETS:
Copy("$TARGET","$SOURCE"),
Chmod("$TARGET", 0644),
])
# install the ogcserver module code
if 'install' in COMMAND_LINE_TARGETS:
ogcserver_files = glob.glob('mapnik/ogcserver/*.py')
ogcserver_module = env.Install(target_path + '/ogcserver', ogcserver_files)
env.Alias(target='install', source=ogcserver_module)
# install the shared object beside the module directory
sources = glob.glob('*.cpp')
py_env = env.Clone()
py_env.Append(CPPPATH = env['PYTHON_INCLUDES'])
@ -194,13 +194,8 @@ if env['HAS_PYCAIRO']:
py_env.ParseConfig('pkg-config --cflags pycairo')
py_env.Append(CXXFLAGS = '-DHAVE_PYCAIRO')
if env['SVN_REVISION']:
sources.remove('mapnik_python.cpp')
env2 = py_env.Clone()
env2.Append(CXXFLAGS='-DSVN_REVISION=%s' % env['SVN_REVISION'])
sources.insert(0,env2.SharedObject('mapnik_python.cpp'))
_mapnik = py_env.LoadableModule('mapnik/_mapnik2', sources, LIBS=libraries, LDMODULEPREFIX='', LDMODULESUFFIX='.so',LINKFLAGS=linkflags)
libraries.append('boost_thread%s' % env['BOOST_APPEND'])
_mapnik = py_env.LoadableModule('mapnik/_mapnik', sources, LIBS=libraries, LDMODULEPREFIX='', LDMODULESUFFIX='.so',LINKFLAGS=linkflags)
Depends(_mapnik, env.subst('../../src/%s' % env['MAPNIK_LIB_NAME']))
@ -219,4 +214,5 @@ if 'uninstall' not in COMMAND_LINE_TARGETS:
env['create_uninstall_target'](env, target_path)
env['create_uninstall_target'](env, target_path_deprecated)

View file

@ -43,7 +43,7 @@ import os
import sys
import warnings
from _mapnik2 import *
from _mapnik import *
from paths import inputpluginspath, fontscollectionpath
import printing
@ -67,13 +67,13 @@ class _MapnikMetaclass(BoostPythonMetaclass):
_injector = _MapnikMetaclass('_injector', (object, ), {})
def Filter(*args,**kwargs):
warnings.warn("'Filter' is deprecated and will be removed in Mapnik 2.0.1, use 'Expression' instead",
warnings.warn("'Filter' is deprecated and will be removed in Mapnik 3.x, use 'Expression' instead",
DeprecationWarning, 2)
return Expression(*args, **kwargs)
class Envelope(Box2d):
def __init__(self, *args, **kwargs):
warnings.warn("'Envelope' is deprecated and will be removed in Mapnik 2.0.1, use 'Box2d' instead",
warnings.warn("'Envelope' is deprecated and will be removed in Mapnik 3.x, use 'Box2d' instead",
DeprecationWarning, 2)
Box2d.__init__(self, *args, **kwargs)
@ -605,13 +605,6 @@ def Geos(**keywords):
keywords['type'] = 'geos'
return CreateDatasource(keywords)
def mapnik_version_string(version=mapnik_version()):
"""Return the Mapnik version as a string."""
patch_level = version % 100
minor_version = version / 100 % 1000
major_version = version / 100000
return '%s.%s.%s' % ( major_version, minor_version,patch_level)
def mapnik_version_from_string(version_string):
"""Return the Mapnik version from a string."""
n = version_string.split('.')
@ -631,105 +624,3 @@ def register_fonts(path=fontscollectionpath,valid_extensions=['.ttf','.otf','.tt
# auto-register known plugins and fonts
register_plugins()
register_fonts()
# Explicitly export API members to avoid namespace pollution
# and ensure correct documentation processing
__all__ = [
# classes
'Color',
'Coord',
'Palette',
#'ColorBand',
'CompositeOp',
'DatasourceCache',
'MemoryDatasource',
'Box2d',
'Feature',
'Featureset',
'FontEngine',
'Geometry2d',
'GlyphSymbolizer',
'Image',
'ImageView',
'Grid',
'GridView',
'Layer',
'Layers',
'LinePatternSymbolizer',
'LineSymbolizer',
'Map',
'MarkersSymbolizer',
'Names',
'Path',
'Parameter',
'Parameters',
'PointDatasource',
'PointSymbolizer',
'PolygonPatternSymbolizer',
'PolygonSymbolizer',
'ProjTransform',
'Projection',
'Query',
'RasterSymbolizer',
'RasterColorizer',
'Rule', 'Rules',
'ShieldSymbolizer',
'Singleton',
'Stroke',
'Style',
'Symbolizer',
'Symbolizers',
'TextSymbolizer',
'ViewTransform',
# enums
'aspect_fix_mode',
'point_placement',
'label_placement',
'line_cap',
'line_join',
'text_transform',
'vertical_alignment',
'horizontal_alignment',
'justify_alignment',
'pattern_alignment',
'filter_mode',
# functions
# datasources
'Datasource',
'CreateDatasource',
'Shapefile',
'PostGIS',
'Raster',
'Gdal',
'Occi',
'Ogr',
'SQLite',
'Osm',
'Kismet',
'Describe',
# version and environment
'mapnik_version_string',
'mapnik_version',
'mapnik_svn_revision',
'has_cairo',
'has_pycairo',
# factory methods
'Expression',
'PathExpression',
# load/save/render
'load_map',
'load_map_from_string',
'save_map',
'save_map_to_string',
'render',
'render_grid',
'render_tile_to_file',
'render_to_file',
# other
'register_plugins',
'register_fonts',
'scale_denominator',
# deprecated
'Filter',
'Envelope',
]

View file

@ -1,125 +0,0 @@
#
# This file is part of Mapnik (c++ mapping toolkit)
#
# Copyright (C) 2006 Jean-Francois Doyon
#
# Mapnik is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# $Id$
"""Interface for registering map styles and layers for availability in WMS Requests."""
from common import Version, copy_style, copy_layer
from exceptions import OGCException, ServerConfigurationError
from wms111 import ServiceHandler as ServiceHandler111
from wms130 import ServiceHandler as ServiceHandler130
from mapnik2 import Style, Map, load_map
import re
import sys
def ServiceHandlerFactory(conf, mapfactory, onlineresource, version):
if not version:
version = Version('1.3.0')
else:
version = Version(version)
if version >= '1.3.0':
return ServiceHandler130(conf, mapfactory, onlineresource)
else:
return ServiceHandler111(conf, mapfactory, onlineresource)
class BaseWMSFactory:
def __init__(self):
self.layers = {}
self.ordered_layers = []
self.styles = {}
self.aggregatestyles = {}
def loadXML(self, xmlfile, strict=False):
tmp_map = Map(0,0)
load_map (tmp_map, xmlfile, strict)
for lyr in tmp_map.layers:
style_count = len(lyr.styles)
if style_count == 0:
raise ServerConfigurationError("Cannot register Layer '%s' without a style" % lyr.name)
elif style_count == 1:
style_obj = tmp_map.find_style(lyr.styles[0])
style_obj = copy_style(style_obj)
style_name = lyr.styles[0]
if style_name not in self.aggregatestyles.keys() and style_name not in self.styles.keys():
self.register_style(style_name, style_obj)
self.register_layer(copy_layer(lyr), style_name, extrastyles=(style_name,))
elif style_count > 1:
for style_name in lyr.styles:
style_obj = tmp_map.find_style(style_name)
style_obj = copy_style(style_obj)
if style_name not in self.aggregatestyles.keys() and style_name not in self.styles.keys():
self.register_style(style_name, style_obj)
aggregates = tuple([sty for sty in lyr.styles])
aggregates_name = '%s_aggregates' % lyr.name
self.register_aggregate_style(aggregates_name,aggregates)
self.register_layer(copy_layer(lyr), aggregates_name, extrastyles=aggregates)
def register_layer(self, layer, defaultstyle, extrastyles=()):
layername = layer.name
if not layername:
raise ServerConfigurationError('Attempted to register an unnamed layer.')
if not re.match('^\+init=epsg:\d+$', layer.srs) and not re.match('^\+proj=.*$', layer.srs):
raise ServerConfigurationError('Attempted to register a layer without an epsg projection defined.')
if defaultstyle not in self.styles.keys() + self.aggregatestyles.keys():
raise ServerConfigurationError('Attempted to register a layer with an non-existent default style.')
layer.wmsdefaultstyle = defaultstyle
if isinstance(extrastyles, tuple):
for stylename in extrastyles:
if type(stylename) == type(''):
if stylename not in self.styles.keys() + self.aggregatestyles.keys():
raise ServerConfigurationError('Attempted to register a layer with an non-existent extra style.')
else:
ServerConfigurationError('Attempted to register a layer with an invalid extra style name.')
layer.wmsextrastyles = extrastyles
else:
raise ServerConfigurationError('Layer "%s" was passed an invalid list of extra styles. List must be a tuple of strings.' % layername)
self.ordered_layers.append(layer)
self.layers[layername] = layer
def register_style(self, name, style):
if not name:
raise ServerConfigurationError('Attempted to register a style without providing a name.')
if name in self.aggregatestyles.keys() or name in self.styles.keys():
raise ServerConfigurationError("Attempted to register a style with a name already in use: '%s'" % name)
if not isinstance(style, Style):
raise ServerConfigurationError('Bad style object passed to register_style() for style "%s".' % name)
self.styles[name] = style
def register_aggregate_style(self, name, stylenames):
if not name:
raise ServerConfigurationError('Attempted to register an aggregate style without providing a name.')
if name in self.aggregatestyles.keys() or name in self.styles.keys():
raise ServerConfigurationError('Attempted to register an aggregate style with a name already in use.')
self.aggregatestyles[name] = []
for stylename in stylenames:
if stylename not in self.styles.keys():
raise ServerConfigurationError('Attempted to register an aggregate style containing a style that does not exist.')
self.aggregatestyles[name].append(stylename)
def finalize(self):
if len(self.layers) == 0:
raise ServerConfigurationError('No layers defined!')
if len(self.styles) == 0:
raise ServerConfigurationError('No styles defined!')
for layer in self.layers.values():
for style in list(layer.styles) + list(layer.wmsextrastyles):
if style not in self.styles.keys() + self.aggregatestyles.keys():
raise ServerConfigurationError('Layer "%s" refers to undefined style "%s".' % (layer.name, style))

View file

@ -1,28 +0,0 @@
#
# This file is part of Mapnik (c++ mapping toolkit)
#
# Copyright (C) 2006 Jean-Francois Doyon
#
# Mapnik is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# $Id$
"""Mapnik OGC WMS Server."""
import os
import warnings
warnings.warn("ogcserver module development has moved to https://github.com/mapnik/OGCServer.\n This code will function fine with this version, but will be removed in Mapnik 2.1.0. Disable this warning by editing this file: %s" % os.path.realpath(__file__), DeprecationWarning, 2)

View file

@ -1,116 +0,0 @@
#
# This file is part of Mapnik (c++ mapping toolkit)
#
# Copyright (C) 2006 Jean-Francois Doyon
#
# Mapnik is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# $Id$
"""CGI/FastCGI handler for Mapnik OGC WMS Server.
Requires 'jon' module.
"""
from os import environ
from tempfile import gettempdir
environ['PYTHON_EGG_CACHE'] = gettempdir()
import sys
from jon import cgi
from exceptions import OGCException, ServerConfigurationError
from wms111 import ExceptionHandler as ExceptionHandler111
from wms130 import ExceptionHandler as ExceptionHandler130
from configparser import SafeConfigParser
from common import Version
class Handler(cgi.DebugHandler):
def __init__(self):
conf = SafeConfigParser()
conf.readfp(open(self.configpath))
self.conf = conf
if not conf.has_option_with_value('server', 'module'):
raise ServerConfigurationError('The factory module is not defined in the configuration file.')
try:
mapfactorymodule = __import__(conf.get('server', 'module'))
except ImportError:
raise ServerConfigurationError('The factory module could not be loaded.')
if hasattr(mapfactorymodule, 'WMSFactory'):
self.mapfactory = getattr(mapfactorymodule, 'WMSFactory')()
else:
raise ServerConfigurationError('The factory module does not have a WMSFactory class.')
if conf.has_option('server', 'debug'):
self.debug = int(conf.get('server', 'debug'))
else:
self.debug = 0
def process(self, req):
reqparams = lowerparams(req.params)
onlineresource = 'http://%s:%s%s?' % (req.environ['SERVER_NAME'], req.environ['SERVER_PORT'], req.environ['SCRIPT_NAME'])
if not reqparams.has_key('request'):
raise OGCException('Missing request parameter.')
request = reqparams['request']
del reqparams['request']
if request == 'GetCapabilities' and not reqparams.has_key('service'):
raise OGCException('Missing service parameter.')
if request in ['GetMap', 'GetFeatureInfo']:
service = 'WMS'
else:
service = reqparams['service']
if reqparams.has_key('service'):
del reqparams['service']
try:
mapnikmodule = __import__('mapnik2.ogcserver.' + service)
except:
raise OGCException('Unsupported service "%s".' % service)
ServiceHandlerFactory = getattr(mapnikmodule.ogcserver, service).ServiceHandlerFactory
servicehandler = ServiceHandlerFactory(self.conf, self.mapfactory, onlineresource, reqparams.get('version', None))
if reqparams.has_key('version'):
del reqparams['version']
if request not in servicehandler.SERVICE_PARAMS.keys():
raise OGCException('Operation "%s" not supported.' % request, 'OperationNotSupported')
ogcparams = servicehandler.processParameters(request, reqparams)
try:
requesthandler = getattr(servicehandler, request)
except:
raise OGCException('Operation "%s" not supported.' % request, 'OperationNotSupported')
response = requesthandler(ogcparams)
req.set_header('Content-Type', response.content_type)
req.set_header('Content-Length', str(len(response.content)))
req.write(response.content)
def traceback(self, req):
reqparams = lowerparams(req.params)
version = reqparams.get('version', None)
if not version:
version = Version('1.3.0')
else:
version = Version(version)
if version >= '1.3.0':
eh = ExceptionHandler130(self.debug)
else:
eh = ExceptionHandler111(self.debug)
response = eh.getresponse(reqparams)
req.set_header('Content-Type', response.content_type)
req.set_header('Content-Length', str(len(response.content)))
req.write(response.content)
def lowerparams(params):
reqparams = {}
for key, value in params.items():
reqparams[key.lower()] = value
return reqparams

View file

@ -1,539 +0,0 @@
#
# This file is part of Mapnik (c++ mapping toolkit)
#
# Copyright (C) 2006 Jean-Francois Doyon
#
# Mapnik is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# $Id$
"""Core OGCServer classes and functions."""
from exceptions import OGCException, ServerConfigurationError
from mapnik2 import Map, Color, Box2d, render, Image, Layer, Style, Projection as MapnikProjection, Coord
from PIL.Image import new
from PIL.ImageDraw import Draw
from StringIO import StringIO
from copy import deepcopy
from traceback import format_exception, format_exception_only
from sys import exc_info
import re
import sys
try:
from lxml import etree as ElementTree
except ImportError:
import xml.etree.ElementTree as ElementTree
except ImportError:
import elementtree.ElementTree as ElementTree
# from elementtree import ElementTree
# ElementTree._namespace_map.update({'http://www.opengis.net/wms': 'wms',
# 'http://www.opengis.net/ogc': 'ogc',
# 'http://www.w3.org/1999/xlink': 'xlink',
# 'http://www.w3.org/2001/XMLSchema-instance': 'xsi'
# })
PIL_TYPE_MAPPING = {'image/jpeg': 'jpeg', 'image/png': 'png'}
class ParameterDefinition:
def __init__(self, mandatory, cast, default=None, allowedvalues=None, fallback=False):
""" An OGC request parameter definition. Used to describe a
parameter's characteristics.
@param mandatory: Is this parameter required by the request?
@type mandatory: Boolean.
@param default: Default value to use if one is not provided
and the parameter is optional.
@type default: None or any valid value.
@param allowedvalues: A list of allowed values for the parameter.
If a value is provided that is not in this
list, an error is raised.
@type allowedvalues: A python tuple of values.
@param fallback: Whether the value of the parameter should fall
back to the default should an illegal value be
provided.
@type fallback: Boolean.
@return: A L{ParameterDefinition} instance.
"""
if mandatory not in [True, False]:
raise ServerConfigurationError("Bad value for 'mandatory' parameter, must be True or False.")
self.mandatory = mandatory
if not callable(cast):
raise ServerConfigurationError('Cast parameter definition must be callable.')
self.cast = cast
self.default = default
if allowedvalues and type(allowedvalues) != type(()):
raise ServerConfigurationError("Bad value for 'allowedvalues' parameter, must be a tuple.")
self.allowedvalues = allowedvalues
if fallback not in [True, False]:
raise ServerConfigurationError("Bad value for 'fallback' parameter, must be True or False.")
self.fallback = fallback
class BaseServiceHandler:
CONF_CONTACT_PERSON_PRIMARY = [
['contactperson', 'ContactPerson', str],
['contactorganization', 'ContactOrganization', str]
]
CONF_CONTACT_ADDRESS = [
['addresstype', 'AddressType', str],
['address', 'Address', str],
['city', 'City', str],
['stateorprovince', 'StateOrProvince', str],
['postcode', 'PostCode', str],
['country', 'Country', str]
]
CONF_CONTACT = [
['contactposition', 'ContactPosition', str],
['contactvoicetelephone', 'ContactVoiceTelephone', str],
['contactelectronicmailaddress', 'ContactElectronicMailAddress', str]
]
def processParameters(self, requestname, params):
finalparams = {}
for paramname, paramdef in self.SERVICE_PARAMS[requestname].items():
if paramname not in params.keys() and paramdef.mandatory:
raise OGCException('Mandatory parameter "%s" missing from request.' % paramname)
elif paramname in params.keys():
try:
params[paramname] = paramdef.cast(params[paramname])
except OGCException:
raise
except:
raise OGCException('Invalid value "%s" for parameter "%s".' % (params[paramname], paramname))
if paramdef.allowedvalues and params[paramname] not in paramdef.allowedvalues:
if not paramdef.fallback:
raise OGCException('Parameter "%s" has an illegal value.' % paramname)
else:
finalparams[paramname] = paramdef.default
else:
finalparams[paramname] = params[paramname]
elif not paramdef.mandatory and paramdef.default:
finalparams[paramname] = paramdef.default
return finalparams
def processServiceCapabilities(self, capetree):
if len(self.conf.items('service')) > 0:
servicee = capetree.find('{http://www.opengis.net/wms}Service')
for item in self.CONF_SERVICE:
if self.conf.has_option_with_value('service', item[0]):
value = self.conf.get('service', item[0]).strip()
try:
item[2](value)
except:
raise ServerConfigurationError('Configuration parameter [%s]->%s has an invalid value: %s.' % ('service', item[0], value))
if item[0] == 'onlineresource':
element = ElementTree.Element('%s' % item[1])
servicee.append(element)
element.set('{http://www.w3.org/1999/xlink}href', value)
element.set('{http://www.w3.org/1999/xlink}type', 'simple')
elif item[0] == 'keywordlist':
element = ElementTree.Element('%s' % item[1])
servicee.append(element)
keywords = value.split(',')
keywords = map(str.strip, keywords)
for keyword in keywords:
kelement = ElementTree.Element('Keyword')
kelement.text = keyword
element.append(kelement)
else:
element = ElementTree.Element('%s' % item[1])
element.text = value
servicee.append(element)
if len(self.conf.items_with_value('contact')) > 0:
element = ElementTree.Element('ContactInformation')
servicee.append(element)
for item in self.CONF_CONTACT:
if self.conf.has_option_with_value('contact', item[0]):
value = self.conf.get('contact', item[0]).strip()
try:
item[2](value)
except:
raise ServerConfigurationError('Configuration parameter [%s]->%s has an invalid value: %s.' % ('service', item[0], value))
celement = ElementTree.Element('%s' % item[1])
celement.text = value
element.append(celement)
for item in self.CONF_CONTACT_PERSON_PRIMARY + self.CONF_CONTACT_ADDRESS:
if item in self.CONF_CONTACT_PERSON_PRIMARY:
tagname = 'ContactPersonPrimary'
else:
tagname = 'ContactAddress'
if self.conf.has_option_with_value('contact', item[0]):
if element.find(tagname) == None:
subelement = ElementTree.Element(tagname)
element.append(subelement)
value = self.conf.get('contact', item[0]).strip()
try:
item[2](value)
except:
raise ServerConfigurationError('Configuration parameter [%s]->%s has an invalid value: %s.' % ('service', item[0], value))
celement = ElementTree.Element('%s' % item[1])
celement.text = value
subelement.append(celement)
class Response:
def __init__(self, content_type, content):
self.content_type = content_type
self.content = content
class Version:
def __init__(self, version):
version = version.split('.')
if len(version) != 3:
raise OGCException('Badly formatted version number.')
try:
version = map(int, version)
except:
raise OGCException('Badly formatted version number.')
self.version = version
def __repr__(self):
return '%s.%s.%s' % (self.version[0], self.version[1], self.version[2])
def __cmp__(self, other):
if isinstance(other, str):
other = Version(other)
if self.version[0] < other.version[0]:
return -1
elif self.version[0] > other.version[0]:
return 1
else:
if self.version[1] < other.version[1]:
return -1
elif self.version[1] > other.version[1]:
return 1
else:
if self.version[2] < other.version[2]:
return -1
elif self.version[2] > other.version[2]:
return 1
else:
return 0
class ListFactory:
def __init__(self, cast):
self.cast = cast
def __call__(self, string):
seq = string.split(',')
return map(self.cast, seq)
def ColorFactory(colorstring):
if re.match('^0x[a-fA-F0-9]{6}$', colorstring):
return Color(eval('0x' + colorstring[2:4]), eval('0x' + colorstring[4:6]), eval('0x' + colorstring[6:8]))
else:
raise OGCException('Invalid color value. Must be of format "0xFFFFFF".')
class CRS:
def __init__(self, namespace, code):
self.namespace = namespace.lower()
self.code = int(code)
self.proj = None
def __repr__(self):
return '%s:%s' % (self.namespace, self.code)
def __eq__(self, other):
if str(other) == str(self):
return True
return False
def inverse(self, x, y):
if not self.proj:
self.proj = Projection('+init=%s:%s' % (self.namespace, self.code))
return self.proj.inverse(Coord(x, y))
def forward(self, x, y):
if not self.proj:
self.proj = Projection('+init=%s:%s' % (self.namespace, self.code))
return self.proj.forward(Coord(x, y))
class CRSFactory:
def __init__(self, allowednamespaces):
self.allowednamespaces = allowednamespaces
def __call__(self, crsstring):
if not re.match('^[A-Z]{3,5}:\d+$', crsstring):
raise OGCException('Invalid format for the CRS parameter: %s' % crsstring, 'InvalidCRS')
crsparts = crsstring.split(':')
if crsparts[0] in self.allowednamespaces:
return CRS(crsparts[0], crsparts[1])
else:
raise OGCException('Invalid CRS Namespace: %s' % crsparts[0], 'InvalidCRS')
def copy_layer(obj):
lyr = Layer(obj.name)
lyr.abstract = obj.abstract
lyr.active = obj.active
lyr.clear_label_cache = obj.clear_label_cache
lyr.datasource = obj.datasource
#lyr.maxzoom = obj.maxzoom
#lyr.minzoom = obj.minzoom
lyr.queryable = obj.queryable
lyr.srs = obj.srs
lyr.title = obj.title
if hasattr(obj,'wmsdefaultstyle'):
lyr.wmsdefaultstyle = obj.wmsdefaultstyle
if hasattr(obj,'wmsextrastyles'):
lyr.wmsextrastyles = obj.wmsextrastyles
return lyr
def copy_style(obj):
sty = Style()
for rule in obj.rules:
sty.rules.append(rule)
return sty
class WMSBaseServiceHandler(BaseServiceHandler):
def GetMap(self, params):
m = self._buildMap(params)
im = Image(params['width'], params['height'])
render(m, im)
return Response(params['format'], im.tostring(PIL_TYPE_MAPPING[params['format']]))
def GetFeatureInfo(self, params, querymethodname='query_point'):
m = self._buildMap(params)
if params['info_format'] == 'text/plain':
writer = TextFeatureInfo()
elif params['info_format'] == 'text/xml':
writer = XMLFeatureInfo()
if params['query_layers'] and params['query_layers'][0] == '__all__':
for layerindex, layer in enumerate(m.layers):
featureset = getattr(m, querymethodname)(layerindex, params['i'], params['j'])
features = featureset.features
if features:
writer.addlayer(layer.name)
for feat in features:
writer.addfeature()
for prop in feat.properties:
writer.addattribute(prop[0], prop[1])
else:
for layerindex, layername in enumerate(params['query_layers']):
if layername in params['layers']:
if m.layers[layerindex].queryable:
featureset = getattr(m, querymethodname)(layerindex, params['i'], params['j'])
features = featureset.features
if features:
writer.addlayer(m.layers[layerindex].name)
for feat in features:
writer.addfeature()
for prop in feat.properties:
writer.addattribute(prop[0], prop[1])
else:
raise OGCException('Requested query layer "%s" is not marked queryable.' % layername, 'LayerNotQueryable')
else:
raise OGCException('Requested query layer "%s" not in the LAYERS parameter.' % layername)
return Response(params['info_format'], str(writer))
def _buildMap(self, params):
if str(params['crs']) not in self.allowedepsgcodes:
raise OGCException('Unsupported CRS "%s" requested.' % str(params['crs']).upper(), 'InvalidCRS')
if params['bbox'][0] >= params['bbox'][2]:
raise OGCException("BBOX values don't make sense. minx is greater than maxx.")
if params['bbox'][1] >= params['bbox'][3]:
raise OGCException("BBOX values don't make sense. miny is greater than maxy.")
if params.has_key('styles') and len(params['styles']) != len(params['layers']):
raise OGCException('STYLES length does not match LAYERS length.')
m = Map(params['width'], params['height'], '+init=%s' % params['crs'])
if params.has_key('transparent') and params['transparent'] == 'FALSE':
if params['bgcolor']:
m.background = params['bgcolor']
else:
m.background = Color(0, 0, 0, 0)
maplayers = self.mapfactory.layers
orderedmaplayers = self.mapfactory.ordered_layers
mapstyles = self.mapfactory.styles
mapaggregatestyles = self.mapfactory.aggregatestyles
# a non WMS spec way of requesting all layers
if params['layers'] and params['layers'][0] == '__all__':
for layername in orderedmaplayers:
layer = copy_layer(layername)
reqstyle = layer.wmsdefaultstyle
if reqstyle in mapaggregatestyles.keys():
for stylename in mapaggregatestyles[reqstyle]:
layer.styles.append(stylename)
else:
layer.styles.append(reqstyle)
for stylename in layer.styles:
if stylename in mapstyles.keys():
m.append_style(stylename, mapstyles[stylename])
m.layers.append(layer)
else:
for layerindex, layername in enumerate(params['layers']):
try:
layer = copy_layer(maplayers[layername])
except KeyError:
raise OGCException('Layer "%s" not defined.' % layername, 'LayerNotDefined')
try:
reqstyle = params['styles'][layerindex]
except IndexError:
reqstyle = ''
if reqstyle and reqstyle not in layer.wmsextrastyles:
raise OGCException('Invalid style "%s" requested for layer "%s".' % (reqstyle, layername), 'StyleNotDefined')
if not reqstyle:
reqstyle = layer.wmsdefaultstyle
if reqstyle in mapaggregatestyles.keys():
for stylename in mapaggregatestyles[reqstyle]:
layer.styles.append(stylename)
else:
layer.styles.append(reqstyle)
for stylename in layer.styles:
if stylename in mapstyles.keys():
m.append_style(stylename, mapstyles[stylename])
else:
raise ServerConfigurationError('Layer "%s" refers to non-existent style "%s".' % (layername, stylename))
m.layers.append(layer)
m.zoom_to_box(Box2d(params['bbox'][0], params['bbox'][1], params['bbox'][2], params['bbox'][3]))
return m
class BaseExceptionHandler:
def __init__(self, debug):
self.debug = debug
def getresponse(self, params):
code = ''
message = '\n'
if not params:
message = '''
<h2>Welcome to the Mapnik OGCServer.</h2>
<h3>Ready to accept map requests...</h5>
<h4>For more info see: <a href="http://trac.mapnik.org/wiki/OgcServer">trac.mapnik.org</a></h4>
'''
return self.htmlhandler('', message)
excinfo = exc_info()
if self.debug:
messagelist = format_exception(excinfo[0], excinfo[1], excinfo[2])
else:
messagelist = format_exception_only(excinfo[0], excinfo[1])
message += ''.join(messagelist)
if isinstance(excinfo[1], OGCException) and len(excinfo[1].args) > 1:
code = excinfo[1].args[1]
exceptions = params.get('exceptions', None)
if self.debug:
return self.htmlhandler(code, message)
if not exceptions or not self.handlers.has_key(exceptions):
exceptions = self.defaulthandler
return self.handlers[exceptions](self, code, message, params)
def htmlhandler(self,code,message):
if code:
resp_text = '<h2>OGCServer Error:</h2><pre>%s</pre>\n<h3>Traceback:</h3><pre>%s</pre>\n' % (message, code)
else:
resp_text = message
return Response('text/html', resp_text)
def xmlhandler(self, code, message, params):
ogcexcetree = deepcopy(self.xmltemplate)
e = ogcexcetree.find(self.xpath)
e.text = message
if code:
e.set('code', code)
return Response(self.xmlmimetype, ElementTree.tostring(ogcexcetree))
def inimagehandler(self, code, message, params):
im = new('RGBA', (int(params['width']), int(params['height'])))
im.putalpha(new('1', (int(params['width']), int(params['height']))))
draw = Draw(im)
for count, line in enumerate(message.strip().split('\n')):
draw.text((12,15*(count+1)), line, fill='#000000')
fh = StringIO()
im.save(fh, PIL_TYPE_MAPPING[params['format']])
fh.seek(0)
return Response(params['format'], fh.read())
def blankhandler(self, code, message, params):
bgcolor = params.get('bgcolor', '#FFFFFF')
bgcolor = bgcolor.replace('0x', '#')
transparent = params.get('transparent', 'FALSE')
if transparent == 'TRUE':
im = new('RGBA', (int(params['width']), int(params['height'])))
im.putalpha(new('1', (int(params['width']), int(params['height']))))
else:
im = new('RGBA', (int(params['width']), int(params['height'])), bgcolor)
fh = StringIO()
im.save(fh, PIL_TYPE_MAPPING[params['format']])
fh.seek(0)
return Response(params['format'], fh.read())
class Projection(MapnikProjection):
def epsgstring(self):
return self.params().split('=')[1].upper()
class TextFeatureInfo:
def __init__(self):
self.buffer = ''
def addlayer(self, name):
self.buffer += '\n[%s]\n' % name
def addfeature(self):
pass#self.buffer += '\n'
def addattribute(self, name, value):
self.buffer += '%s=%s\n' % (name, str(value))
def __str__(self):
return self.buffer
class XMLFeatureInfo:
basexml = """<?xml version="1.0"?>
<resultset>
</resultset>
"""
def __init__(self):
self.rootelement = ElementTree.fromstring(self.basexml)
def addlayer(self, name):
layer = ElementTree.Element('layer')
layer.set('name', name)
self.rootelement.append(layer)
self.currentlayer = layer
def addfeature(self):
feature = ElementTree.Element('feature')
self.currentlayer.append(feature)
self.currentfeature = feature
def addattribute(self, name, value):
attribute = ElementTree.Element('attribute')
attname = ElementTree.Element('name')
attname.text = name
attvalue = ElementTree.Element('value')
attvalue.text = unicode(value)
attribute.append(attname)
attribute.append(attvalue)
self.currentfeature.append(attribute)
def __str__(self):
return '<?xml version="1.0"?>\n' + ElementTree.tostring(self.rootelement)

View file

@ -1,44 +0,0 @@
#
# This file is part of Mapnik (c++ mapping toolkit)
#
# Copyright (C) 2006 Jean-Francois Doyon
#
# Mapnik is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# $Id$
""" Change SafeConfigParser behavior to treat options without values as
non-existent.
"""
from ConfigParser import SafeConfigParser as OrigSafeConfigParser
class SafeConfigParser(OrigSafeConfigParser):
def items_with_value(self, section):
finallist = []
items = self.items(section)
for item in items:
if item[1] != '':
finallist.append(item)
return finallist
def has_option_with_value(self, section, option):
if self.has_option(section, option):
if self.get(section, option) == '':
return False
else:
return False
return True

View file

@ -1,28 +0,0 @@
#
# This file is part of Mapnik (c++ mapping toolkit)
#
# Copyright (C) 2006 Jean-Francois Doyon
#
# Mapnik is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# $Id$
"""Custom OGCServer Exceptions"""
class OGCException(Exception):
pass
class ServerConfigurationError(Exception):
pass

View file

@ -1,133 +0,0 @@
#
# This file is part of Mapnik (c++ mapping toolkit)
#
# Copyright (C) 2006 Jean-Francois Doyon
#
# Mapnik is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# $Id: modserver.py 283 2006-07-22 18:54:53Z jdoyon $
"""Mod_python handler for Mapnik OGC WMS Server."""
import sys
from mod_python import apache, util
from exceptions import OGCException, ServerConfigurationError
from wms111 import ExceptionHandler as ExceptionHandler111
from wms130 import ExceptionHandler as ExceptionHandler130
from configparser import SafeConfigParser
from common import Version
class ModHandler(object):
def __init__(self, configpath):
conf = SafeConfigParser()
conf.readfp(open(configpath))
self.conf = conf
if not conf.has_option_with_value('server', 'module'):
raise ServerConfigurationError('The factory module is not defined in the configuration file.')
try:
mapfactorymodule = __import__(conf.get('server', 'module'))
except ImportError:
raise ServerConfigurationError('The factory module could not be loaded.')
if hasattr(mapfactorymodule, 'WMSFactory'):
self.mapfactory = getattr(mapfactorymodule, 'WMSFactory')()
else:
raise ServerConfigurationError('The factory module does not have a WMSFactory class.')
if conf.has_option('server', 'debug'):
self.debug = int(conf.get('server', 'debug'))
else:
self.debug = 0
if self.conf.has_option_with_value('server', 'maxage'):
self.max_age = 'max-age=%d' % self.conf.get('server', 'maxage')
else:
self.max_age = None
def __call__(self, apacheReq):
try:
reqparams = util.FieldStorage(apacheReq,keep_blank_values=1)
if not reqparams:
eh = ExceptionHandler130(self.debug)
response = eh.getresponse(reqparams)
apacheReq.content_type = response.content_type
else:
reqparams = lowerparams(reqparams)
port = apacheReq.connection.local_addr[1]
onlineresource = 'http://%s:%s%s?' % (apacheReq.hostname, port, apacheReq.subprocess_env['SCRIPT_NAME'])
if not reqparams.has_key('request'):
raise OGCException('Missing Request parameter.')
request = reqparams['request']
del reqparams['request']
if request == 'GetCapabilities' and not reqparams.has_key('service'):
raise OGCException('Missing service parameter.')
if request in ['GetMap', 'GetFeatureInfo']:
service = 'WMS'
else:
service = reqparams['service']
if reqparams.has_key('service'):
del reqparams['service']
try:
mapnikmodule = __import__('mapnik2.ogcserver.' + service)
except:
raise OGCException('Unsupported service "%s".' % service)
ServiceHandlerFactory = getattr(mapnikmodule.ogcserver, service).ServiceHandlerFactory
servicehandler = ServiceHandlerFactory(self.conf, self.mapfactory, onlineresource, reqparams.get('version', None))
if reqparams.has_key('version'):
del reqparams['version']
if request not in servicehandler.SERVICE_PARAMS.keys():
raise OGCException('Operation "%s" not supported.' % request, 'OperationNotSupported')
# Get parameters and pass to WMSFactory in custom "setup" method
ogcparams = servicehandler.processParameters(request, reqparams)
try:
requesthandler = getattr(servicehandler, request)
except:
raise OGCException('Operation "%s" not supported.' % request, 'OperationNotSupported')
response = requesthandler(ogcparams)
apacheReq.content_type = response.content_type
apacheReq.status = apache.HTTP_OK
except Exception, E:
return self.traceback(apacheReq,E)
if self.max_age:
apacheReq.headers_out.add('Cache-Control', max_age)
apacheReq.headers_out.add('Content-Length', str(len(response.content)))
apacheReq.send_http_header()
apacheReq.write(response.content)
return apache.OK
def traceback(self, apacheReq,E):
reqparams = lowerparams(util.FieldStorage(apacheReq))
version = reqparams.get('version', None)
if not version:
version = Version('1.3.0')
else:
version = Version(version)
if version >= '1.3.0':
eh = ExceptionHandler130(self.debug)
else:
eh = ExceptionHandler111(self.debug)
response = eh.getresponse(reqparams)
apacheReq.content_type = response.content_type
apacheReq.headers_out.add('Content-Length', str(len(response.content)))
apacheReq.send_http_header()
apacheReq.write(response.content)
return apache.OK
def lowerparams(params):
reqparams = {}
for key, value in params.items():
reqparams[key.lower()] = value
return reqparams

View file

@ -1,238 +0,0 @@
#
# This file is part of Mapnik (c++ mapping toolkit)
#
# Copyright (C) 2006 Jean-Francois Doyon
#
# Mapnik is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# $Id$
"""WMS 1.1.1 compliant GetCapabilities, GetMap, GetFeatureInfo, and Exceptions interface."""
from common import ParameterDefinition, Response, Version, ListFactory, \
ColorFactory, CRSFactory, WMSBaseServiceHandler, CRS, \
BaseExceptionHandler, Projection
from exceptions import OGCException, ServerConfigurationError
from mapnik2 import Coord
try:
from lxml import etree as ElementTree
except ImportError:
import xml.etree.ElementTree as ElementTree
except ImportError:
import elementtree.ElementTree as ElementTree
class ServiceHandler(WMSBaseServiceHandler):
SERVICE_PARAMS = {
'GetCapabilities': {
'updatesequence': ParameterDefinition(False, str)
},
'GetMap': {
'layers': ParameterDefinition(True, ListFactory(str)),
'styles': ParameterDefinition(True, ListFactory(str)),
'srs': ParameterDefinition(True, CRSFactory(['EPSG'])),
'bbox': ParameterDefinition(True, ListFactory(float)),
'width': ParameterDefinition(True, int),
'height': ParameterDefinition(True, int),
'format': ParameterDefinition(True, str, allowedvalues=('image/png', 'image/jpeg')),
'transparent': ParameterDefinition(False, str, 'FALSE', ('TRUE', 'FALSE')),
'bgcolor': ParameterDefinition(False, ColorFactory, ColorFactory('0xFFFFFF')),
'exceptions': ParameterDefinition(False, str, 'application/vnd.ogc.se_xml', ('application/vnd.ogc.se_xml', 'application/vnd.ogc.se_inimage', 'application/vnd.ogc.se_blank','text/html'))
},
'GetFeatureInfo': {
'layers': ParameterDefinition(True, ListFactory(str)),
'styles': ParameterDefinition(False, ListFactory(str)),
'srs': ParameterDefinition(True, CRSFactory(['EPSG'])),
'bbox': ParameterDefinition(True, ListFactory(float)),
'width': ParameterDefinition(True, int),
'height': ParameterDefinition(True, int),
'format': ParameterDefinition(False, str, allowedvalues=('image/png', 'image/jpeg')),
'transparent': ParameterDefinition(False, str, 'FALSE', ('TRUE', 'FALSE')),
'bgcolor': ParameterDefinition(False, ColorFactory, ColorFactory('0xFFFFFF')),
'exceptions': ParameterDefinition(False, str, 'application/vnd.ogc.se_xml', ('application/vnd.ogc.se_xml', 'application/vnd.ogc.se_inimage', 'application/vnd.ogc.se_blank','text/html')),
'query_layers': ParameterDefinition(True, ListFactory(str)),
'info_format': ParameterDefinition(True, str, allowedvalues=('text/plain', 'text/xml')),
'feature_count': ParameterDefinition(False, int, 1),
'x': ParameterDefinition(True, int),
'y': ParameterDefinition(True, int)
}
}
CONF_SERVICE = [
['title', 'Title', str],
['abstract', 'Abstract', str],
['onlineresource', 'OnlineResource', str],
['fees', 'Fees', str],
['accessconstraints', 'AccessConstraints', str],
['keywordlist', 'KeywordList', str]
]
capabilitiesxmltemplate = """<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE WMT_MS_Capabilities SYSTEM "http://www.digitalearth.gov/wmt/xml/capabilities_1_1_1.dtd">
<WMT_MS_Capabilities version="1.1.1" updateSequence="0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.opengis.net/wms">
<Service>
<Name>WMS</Name>
</Service>
<Capability>
<Request>
<GetCapabilities>
<Format>application/vnd.ogc.wms_xml</Format>
<DCPType>
<HTTP>
<Get>
<OnlineResource xlink:type="simple"/>
</Get>
</HTTP>
</DCPType>
</GetCapabilities>
<GetMap>
<Format>image/png</Format>
<Format>image/jpeg</Format>
<DCPType>
<HTTP>
<Get>
<OnlineResource xlink:type="simple"/>
</Get>
</HTTP>
</DCPType>
</GetMap>
<GetFeatureInfo>
<Format>text/plain</Format>
<DCPType>
<HTTP>
<Get>
<OnlineResource xlink:type="simple"/>
</Get>
</HTTP>
</DCPType>
</GetFeatureInfo>
</Request>
<Exception>
<Format>application/vnd.ogc.se_xml</Format>
<Format>application/vnd.ogc.se_inimage</Format>
<Format>application/vnd.ogc.se_blank</Format>
</Exception>
<Layer>
<Title>A Mapnik WMS Server</Title>
<Abstract>A Mapnik WMS Server</Abstract>
</Layer>
</Capability>
</WMT_MS_Capabilities>
"""
def __init__(self, conf, mapfactory, opsonlineresource):
self.conf = conf
self.mapfactory = mapfactory
self.opsonlineresource = opsonlineresource
if self.conf.has_option('service', 'allowedepsgcodes'):
self.allowedepsgcodes = map(lambda code: 'epsg:%s' % code, self.conf.get('service', 'allowedepsgcodes').split(','))
else:
raise ServerConfigurationError('Allowed EPSG codes not properly configured.')
self.capabilities = None
def GetCapabilities(self, params):
if not self.capabilities:
capetree = ElementTree.fromstring(self.capabilitiesxmltemplate)
elements = capetree.findall('Capability//OnlineResource')
for element in elements:
element.set('{http://www.w3.org/1999/xlink}href', self.opsonlineresource)
self.processServiceCapabilities(capetree)
rootlayerelem = capetree.find('{http://www.opengis.net/wms}Capability/{http://www.opengis.net/wms}Layer')
for epsgcode in self.allowedepsgcodes:
rootlayercrs = ElementTree.Element('SRS')
rootlayercrs.text = epsgcode.upper()
rootlayerelem.append(rootlayercrs)
for layer in self.mapfactory.ordered_layers:
layerproj = Projection(layer.srs)
layername = ElementTree.Element('Name')
layername.text = layer.name
env = layer.envelope()
llp = layerproj.inverse(Coord(env.minx, env.miny))
urp = layerproj.inverse(Coord(env.maxx, env.maxy))
latlonbb = ElementTree.Element('LatLonBoundingBox')
latlonbb.set('minx', str(llp.x))
latlonbb.set('miny', str(llp.y))
latlonbb.set('maxx', str(urp.x))
latlonbb.set('maxy', str(urp.y))
layerbbox = ElementTree.Element('BoundingBox')
layerbbox.set('SRS', layerproj.epsgstring())
layerbbox.set('minx', str(env.minx))
layerbbox.set('miny', str(env.miny))
layerbbox.set('maxx', str(env.maxx))
layerbbox.set('maxy', str(env.maxy))
layere = ElementTree.Element('Layer')
layere.append(layername)
if layer.title:
layertitle = ElementTree.Element('Title')
layertitle.text = layer.title
layere.append(layertitle)
if layer.abstract:
layerabstract = ElementTree.Element('Abstract')
layerabstract.text = layer.abstract
layere.append(layerabstract)
if layer.queryable:
layere.set('queryable', '1')
layere.append(latlonbb)
layere.append(layerbbox)
if len(layer.wmsextrastyles) > 0:
for extrastyle in [layer.wmsdefaultstyle] + list(layer.wmsextrastyles):
style = ElementTree.Element('Style')
stylename = ElementTree.Element('Name')
stylename.text = extrastyle
styletitle = ElementTree.Element('Title')
styletitle.text = extrastyle
style.append(stylename)
style.append(styletitle)
layere.append(style)
rootlayerelem.append(layere)
self.capabilities = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>\n' + ElementTree.tostring(capetree)
response = Response('application/vnd.ogc.wms_xml', self.capabilities)
return response
def GetMap(self, params):
params['crs'] = params['srs']
return WMSBaseServiceHandler.GetMap(self, params)
def GetFeatureInfo(self, params):
params['crs'] = params['srs']
params['i'] = params['x']
params['j'] = params['y']
return WMSBaseServiceHandler.GetFeatureInfo(self, params, 'query_map_point')
class ExceptionHandler(BaseExceptionHandler):
xmlmimetype = "application/vnd.ogc.se_xml"
xmltemplate = ElementTree.fromstring("""<?xml version='1.0' encoding="UTF-8" standalone="no"?>
<!DOCTYPE ServiceExceptionReport SYSTEM "http://www.digitalearth.gov/wmt/xml/exception_1_1_1.dtd">
<ServiceExceptionReport version="1.1.1">
<ServiceException />
</ServiceExceptionReport>
""")
xpath = 'ServiceException'
handlers = {'application/vnd.ogc.se_xml': BaseExceptionHandler.xmlhandler,
'application/vnd.ogc.se_inimage': BaseExceptionHandler.inimagehandler,
'application/vnd.ogc.se_blank': BaseExceptionHandler.blankhandler,
'text/html': BaseExceptionHandler.htmlhandler}
defaulthandler = 'application/vnd.ogc.se_xml'

View file

@ -1,264 +0,0 @@
#
# This file is part of Mapnik (c++ mapping toolkit)
#
# Copyright (C) 2006 Jean-Francois Doyon
#
# Mapnik is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# $Id$
"""WMS 1.3.0 compliant GetCapabilities, GetMap, GetFeatureInfo, and Exceptions interface."""
from common import ParameterDefinition, Response, Version, ListFactory, \
ColorFactory, CRSFactory, CRS, WMSBaseServiceHandler, \
BaseExceptionHandler, Projection, Box2d
from exceptions import OGCException, ServerConfigurationError
from mapnik2 import Coord
try:
from lxml import etree as ElementTree
except ImportError:
import xml.etree.ElementTree as ElementTree
except ImportError:
import elementtree.ElementTree as ElementTree
class ServiceHandler(WMSBaseServiceHandler):
SERVICE_PARAMS = {
'GetCapabilities': {
'format': ParameterDefinition(False, str, 'text/xml', ('text/xml',), True),
'updatesequence': ParameterDefinition(False, str)
},
'GetMap': {
'layers': ParameterDefinition(True, ListFactory(str)),
'styles': ParameterDefinition(True, ListFactory(str)),
'crs': ParameterDefinition(True, CRSFactory(['EPSG'])),
'bbox': ParameterDefinition(True, ListFactory(float)),
'width': ParameterDefinition(True, int),
'height': ParameterDefinition(True, int),
'format': ParameterDefinition(True, str, allowedvalues=('image/png', 'image/jpeg')),
'transparent': ParameterDefinition(False, str, 'FALSE', ('TRUE', 'FALSE')),
'bgcolor': ParameterDefinition(False, ColorFactory, ColorFactory('0xFFFFFF')),
'exceptions': ParameterDefinition(False, str, 'XML', ('XML', 'INIMAGE', 'BLANK','HTML')),
},
'GetFeatureInfo': {
'layers': ParameterDefinition(True, ListFactory(str)),
'styles': ParameterDefinition(False, ListFactory(str)),
'crs': ParameterDefinition(True, CRSFactory(['EPSG'])),
'bbox': ParameterDefinition(True, ListFactory(float)),
'width': ParameterDefinition(True, int),
'height': ParameterDefinition(True, int),
'format': ParameterDefinition(False, str, allowedvalues=('image/png', 'image/jpeg')),
'transparent': ParameterDefinition(False, str, 'FALSE', ('TRUE', 'FALSE')),
'bgcolor': ParameterDefinition(False, ColorFactory, ColorFactory('0xFFFFFF')),
'exceptions': ParameterDefinition(False, str, 'XML', ('XML', 'INIMAGE', 'BLANK','HTML')),
'query_layers': ParameterDefinition(True, ListFactory(str)),
'info_format': ParameterDefinition(True, str, allowedvalues=('text/plain', 'text/xml')),
'feature_count': ParameterDefinition(False, int, 1),
'i': ParameterDefinition(True, float),
'j': ParameterDefinition(True, float)
}
}
CONF_SERVICE = [
['title', 'Title', str],
['abstract', 'Abstract', str],
['onlineresource', 'OnlineResource', str],
['fees', 'Fees', str],
['accessconstraints', 'AccessConstraints', str],
['layerlimit', 'LayerLimit', int],
['maxwidth', 'MaxWidth', int],
['maxheight', 'MaxHeight', int],
['keywordlist', 'KeywordList', str]
]
capabilitiesxmltemplate = """<?xml version="1.0" encoding="UTF-8"?>
<WMS_Capabilities version="1.3.0" xmlns="http://www.opengis.net/wms"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/wms http://schemas.opengis.net/wms/1.3.0/capabilities_1_3_0.xsd">
<Service>
<Name>WMS</Name>
</Service>
<Capability>
<Request>
<GetCapabilities>
<Format>text/xml</Format>
<DCPType>
<HTTP>
<Get>
<OnlineResource xlink:type="simple"/>
</Get>
</HTTP>
</DCPType>
</GetCapabilities>
<GetMap>
<Format>image/png</Format>
<Format>image/jpeg</Format>
<DCPType>
<HTTP>
<Get>
<OnlineResource xlink:type="simple"/>
</Get>
</HTTP>
</DCPType>
</GetMap>
<GetFeatureInfo>
<Format>text/plain</Format>
<DCPType>
<HTTP>
<Get>
<OnlineResource xlink:type="simple"/>
</Get>
</HTTP>
</DCPType>
</GetFeatureInfo>
</Request>
<Exception>
<Format>XML</Format>
<Format>INIMAGE</Format>
<Format>BLANK</Format>
</Exception>
<Layer>
<Title>A Mapnik WMS Server</Title>
<Abstract>A Mapnik WMS Server</Abstract>
</Layer>
</Capability>
</WMS_Capabilities>
"""
def __init__(self, conf, mapfactory, opsonlineresource):
self.conf = conf
self.mapfactory = mapfactory
self.opsonlineresource = opsonlineresource
if self.conf.has_option('service', 'allowedepsgcodes'):
self.allowedepsgcodes = map(lambda code: 'epsg:%s' % code, self.conf.get('service', 'allowedepsgcodes').split(','))
else:
raise ServerConfigurationError('Allowed EPSG codes not properly configured.')
self.capabilities = None
def GetCapabilities(self, params):
if not self.capabilities:
capetree = ElementTree.fromstring(self.capabilitiesxmltemplate)
elements = capetree.findall('{http://www.opengis.net/wms}Capability//{http://www.opengis.net/wms}OnlineResource')
for element in elements:
element.set('{http://www.w3.org/1999/xlink}href', self.opsonlineresource)
self.processServiceCapabilities(capetree)
rootlayerelem = capetree.find('{http://www.opengis.net/wms}Capability/{http://www.opengis.net/wms}Layer')
for epsgcode in self.allowedepsgcodes:
rootlayercrs = ElementTree.Element('CRS')
rootlayercrs.text = epsgcode.upper()
rootlayerelem.append(rootlayercrs)
for layer in self.mapfactory.ordered_layers:
layerproj = Projection(layer.srs)
layername = ElementTree.Element('Name')
layername.text = layer.name
env = layer.envelope()
layerexgbb = ElementTree.Element('EX_GeographicBoundingBox')
ll = layerproj.inverse(Coord(env.minx, env.miny))
ur = layerproj.inverse(Coord(env.maxx, env.maxy))
exgbb_wbl = ElementTree.Element('westBoundLongitude')
exgbb_wbl.text = str(ll.x)
layerexgbb.append(exgbb_wbl)
exgbb_ebl = ElementTree.Element('eastBoundLongitude')
exgbb_ebl.text = str(ur.x)
layerexgbb.append(exgbb_ebl)
exgbb_sbl = ElementTree.Element('southBoundLatitude')
exgbb_sbl.text = str(ll.y)
layerexgbb.append(exgbb_sbl)
exgbb_nbl = ElementTree.Element('northBoundLatitude')
exgbb_nbl.text = str(ur.y)
layerexgbb.append(exgbb_nbl)
layerbbox = ElementTree.Element('BoundingBox')
layerbbox.set('CRS', layerproj.epsgstring())
layerbbox.set('minx', str(env.minx))
layerbbox.set('miny', str(env.miny))
layerbbox.set('maxx', str(env.maxx))
layerbbox.set('maxy', str(env.maxy))
layere = ElementTree.Element('Layer')
layere.append(layername)
if layer.title:
layertitle = ElementTree.Element('Title')
layertitle.text = layer.title
layere.append(layertitle)
if layer.abstract:
layerabstract = ElementTree.Element('Abstract')
layerabstract.text = layer.abstract
layere.append(layerabstract)
if layer.queryable:
layere.set('queryable', '1')
layere.append(layerexgbb)
layere.append(layerbbox)
if len(layer.wmsextrastyles) > 0:
for extrastyle in [layer.wmsdefaultstyle] + list(layer.wmsextrastyles):
style = ElementTree.Element('Style')
stylename = ElementTree.Element('Name')
stylename.text = extrastyle
styletitle = ElementTree.Element('Title')
styletitle.text = extrastyle
style.append(stylename)
style.append(styletitle)
layere.append(style)
rootlayerelem.append(layere)
self.capabilities = '<?xml version="1.0" encoding="UTF-8"?>' + ElementTree.tostring(capetree)
response = Response('text/xml', self.capabilities)
return response
def GetMap(self, params):
if params['width'] > int(self.conf.get('service', 'maxwidth')) or params['height'] > int(self.conf.get('service', 'maxheight')):
raise OGCException('Requested map size exceeds limits set by this server.')
return WMSBaseServiceHandler.GetMap(self, params)
def _buildMap(self, params):
""" Override _buildMap method to handle reverse axis ordering in WMS 1.3.0.
More info: http://mapserver.org/development/rfc/ms-rfc-30.html
'when using epsg code >=4000 and <5000 will be assumed to have a reversed axes.'
"""
# Call superclass method
m = WMSBaseServiceHandler._buildMap(self, params)
# for range of epsg codes reverse axis
if params['crs'].code >= 4000 and params['crs'].code < 5000:
m.zoom_to_box(Box2d(params['bbox'][1], params['bbox'][0], params['bbox'][3], params['bbox'][2]))
return m
class ExceptionHandler(BaseExceptionHandler):
xmlmimetype = "text/xml"
xmltemplate = ElementTree.fromstring("""<?xml version='1.0' encoding="UTF-8"?>
<ServiceExceptionReport version="1.3.0"
xmlns="http://www.opengis.net/ogc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/ogc http://schemas.opengis.net/wms/1.3.0/exceptions_1_3_0.xsd">
<ServiceException/>
</ServiceExceptionReport>
""")
xpath = '{http://www.opengis.net/ogc}ServiceException'
handlers = {'XML': BaseExceptionHandler.xmlhandler,
'INIMAGE': BaseExceptionHandler.inimagehandler,
'BLANK': BaseExceptionHandler.blankhandler,
'HTML': BaseExceptionHandler.htmlhandler}
defaulthandler = 'XML'

View file

@ -1,106 +0,0 @@
#
# This file is part of Mapnik (c++ mapping toolkit)
#
# Copyright (C) 2006 Jean-Francois Doyon
#
# Mapnik is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# $Id$
"""WSGI application wrapper for Mapnik OGC WMS Server."""
from exceptions import OGCException, ServerConfigurationError
from configparser import SafeConfigParser
from cgi import parse_qs
from wms111 import ExceptionHandler as ExceptionHandler111
from wms130 import ExceptionHandler as ExceptionHandler130
from common import Version
class WSGIApp:
def __init__(self, configpath):
conf = SafeConfigParser()
conf.readfp(open(configpath))
self.conf = conf
if not conf.has_option_with_value('server', 'module'):
raise ServerConfigurationError('The factory module is not defined in the configuration file.')
try:
mapfactorymodule = __import__(conf.get('server', 'module'))
except ImportError:
raise ServerConfigurationError('The factory module could not be loaded.')
if hasattr(mapfactorymodule, 'WMSFactory'):
self.mapfactory = getattr(mapfactorymodule, 'WMSFactory')()
else:
raise ServerConfigurationError('The factory module does not have a WMSFactory class.')
if conf.has_option('server', 'debug'):
self.debug = int(conf.get('server', 'debug'))
else:
self.debug = 0
if self.conf.has_option_with_value('server', 'maxage'):
self.max_age = 'max-age=%d' % self.conf.get('server', 'maxage')
else:
self.max_age = None
def __call__(self, environ, start_response):
reqparams = {}
for key, value in parse_qs(environ['QUERY_STRING'], True).items():
reqparams[key.lower()] = value[0]
onlineresource = 'http://%s:%s%s?' % (environ['SERVER_NAME'], environ['SERVER_PORT'], environ['PATH_INFO'])
try:
if not reqparams.has_key('request'):
raise OGCException('Missing request parameter.')
request = reqparams['request']
del reqparams['request']
if request == 'GetCapabilities' and not reqparams.has_key('service'):
raise OGCException('Missing service parameter.')
if request in ['GetMap', 'GetFeatureInfo']:
service = 'WMS'
else:
service = reqparams['service']
if reqparams.has_key('service'):
del reqparams['service']
try:
mapnikmodule = __import__('mapnik2.ogcserver.' + service)
except:
raise OGCException('Unsupported service "%s".' % service)
ServiceHandlerFactory = getattr(mapnikmodule.ogcserver, service).ServiceHandlerFactory
servicehandler = ServiceHandlerFactory(self.conf, self.mapfactory, onlineresource, reqparams.get('version', None))
if reqparams.has_key('version'):
del reqparams['version']
if request not in servicehandler.SERVICE_PARAMS.keys():
raise OGCException('Operation "%s" not supported.' % request, 'OperationNotSupported')
ogcparams = servicehandler.processParameters(request, reqparams)
try:
requesthandler = getattr(servicehandler, request)
except:
raise OGCException('Operation "%s" not supported.' % request, 'OperationNotSupported')
response = requesthandler(ogcparams)
except:
version = reqparams.get('version', None)
if not version:
version = Version('1.3.0')
else:
version = Version(version)
if version >= '1.3.0':
eh = ExceptionHandler130(self.debug)
else:
eh = ExceptionHandler111(self.debug)
response = eh.getresponse(reqparams)
response_headers = [('Content-Type', response.content_type),('Content-Length', str(len(response.content)))]
if self.max_age:
response_headers.append(('Cache-Control', max_age))
start_response('200 OK', response_headers)
yield response.content

View file

@ -4,17 +4,18 @@
basic usage is along the lines of
import mapnik2
import mapnik
page = mapnik2.printing.PDFPrinter()
m = mapnik2.Map(100,100)
mapnik2.load_map(m, "my_xml_map_description", True)
page = mapnik.printing.PDFPrinter()
m = mapnik.Map(100,100)
mapnik.load_map(m, "my_xml_map_description", True)
m.zoom_all()
page.render_map(m,"my_output_file.pdf")
see the documentation of mapnik2.printing.PDFPrinter() for options
see the documentation of mapnik.printing.PDFPrinter() for options
"""
from __future__ import absolute_import
from . import render, Map, Box2d, MemoryDatasource, Layer, Feature, Projection, ProjTransform, Coord, Style, Rule, Geometry2d
import math

View file

@ -0,0 +1,27 @@
#
# This file is part of Mapnik (C++/Python mapping toolkit)
# Copyright (C) 2011 Artem Pavlenko
#
# Mapnik is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# mapnik2 module (Deprecated)
import warnings
from mapnik import *
warnings.simplefilter("default")
msg=""" mapnik2 module has been deprecated,
please use 'import mapnik' """
warnings.warn(msg, DeprecationWarning)

View file

@ -71,15 +71,15 @@ void export_featureset()
.def("__iter__",pass_through)
.def("next",next)
.add_property("features",features,
"The list of features.\n"
"\n"
"Usage:\n"
">>> m.query_map_point(0, 10, 10)\n"
"<mapnik2._mapnik2.Featureset object at 0x1004d2938>\n"
">>> fs = m.query_map_point(0, 10, 10)\n"
">>> for f in fs.features:\n"
">>> print f\n"
"<mapnik2.Feature object at 0x105e64140>\n"
"The list of features.\n"
"\n"
"Usage:\n"
">>> m.query_map_point(0, 10, 10)\n"
"<mapnik._mapnik.Featureset object at 0x1004d2938>\n"
">>> fs = m.query_map_point(0, 10, 10)\n"
">>> for f in fs.features:\n"
">>> print f\n"
"<mapnik.Feature object at 0x105e64140>\n"
)
;
}

View file

@ -60,7 +60,8 @@ struct markers_symbolizer_pickle_suite : boost::python::pickle_suite
static boost::python::tuple
getstate(markers_symbolizer const& p)
{
return boost::python::make_tuple(p.get_allow_overlap());//,p.get_opacity());
return boost::python::make_tuple(p.get_allow_overlap(),
p.get_ignore_placement());//,p.get_opacity());
}
static void
@ -77,8 +78,7 @@ struct markers_symbolizer_pickle_suite : boost::python::pickle_suite
}
p.set_allow_overlap(extract<bool>(state[0]));
//p.set_opacity(extract<float>(state[1]));
p.set_ignore_placement(extract<bool>(state[1]));
}
};
@ -108,8 +108,19 @@ void export_markers_symbolizer()
&markers_symbolizer::get_opacity,
&markers_symbolizer::set_opacity,
"Set/get the text opacity")
.add_property("ignore_placement",
&markers_symbolizer::get_ignore_placement,
&markers_symbolizer::set_ignore_placement)
.add_property("transform",
&mapnik::get_svg_transform<markers_symbolizer>,
&mapnik::set_svg_transform<markers_symbolizer>)
.add_property("width",
&markers_symbolizer::get_width,
&markers_symbolizer::set_width,
"Set/get the marker width")
.add_property("height",
&markers_symbolizer::get_height,
&markers_symbolizer::set_height,
"Set/get the marker height")
;
}

View file

@ -319,13 +319,9 @@ unsigned mapnik_version()
return MAPNIK_VERSION;
}
unsigned mapnik_svn_revision()
std::string mapnik_version_string()
{
#if defined(SVN_REVISION)
return SVN_REVISION;
#else
return 0;
#endif
return MAPNIK_VERSION_STRING;
}
// indicator for jpeg read/write support within libmapnik
@ -375,7 +371,7 @@ BOOST_PYTHON_FUNCTION_OVERLOADS(save_map_overloads, save_map, 2, 3)
BOOST_PYTHON_FUNCTION_OVERLOADS(save_map_to_string_overloads, save_map_to_string, 1, 2)
BOOST_PYTHON_FUNCTION_OVERLOADS(render_overloads, render, 2, 5)
BOOST_PYTHON_MODULE(_mapnik2)
BOOST_PYTHON_MODULE(_mapnik)
{
using namespace boost::python;
@ -606,7 +602,7 @@ BOOST_PYTHON_MODULE(_mapnik2)
def("save_map_to_string", &save_map_to_string, save_map_to_string_overloads());
def("mapnik_version", &mapnik_version,"Get the Mapnik version number");
def("mapnik_svn_revision", &mapnik_svn_revision,"Get the Mapnik svn revision");
def("mapnik_version_string", &mapnik_version_string,"Get the Mapnik version string");
def("has_jpeg", &has_jpeg, "Get jpeg read/write support status");
def("has_cairo", &has_cairo, "Get cairo library status");
def("has_pycairo", &has_pycairo, "Get pycairo module status");

View file

@ -105,51 +105,51 @@ void export_raster_colorizer()
">>> colorizer.add_stop(stop)\n"
)
.def("add_stop", add_stop2,
(arg("value")),
"Add a colorizer stop to the raster colorizer, using the default mode and color.\n"
"\n"
"Usage:\n"
">>> default_color = mapnik.Color(\"#0044cc\")\n"
">>> colorizer = mapnik.RasterColorizer(mapnik2.COLORIZER_LINEAR, default_color)\n"
">>> colorizer.add_stop(100)\n"
(arg("value")),
"Add a colorizer stop to the raster colorizer, using the default mode and color.\n"
"\n"
"Usage:\n"
">>> default_color = mapnik.Color(\"#0044cc\")\n"
">>> colorizer = mapnik.RasterColorizer(mapnik.COLORIZER_LINEAR, default_color)\n"
">>> colorizer.add_stop(100)\n"
)
.def("add_stop", add_stop3,
(arg("value")),
"Add a colorizer stop to the raster colorizer, using the default mode.\n"
"\n"
"Usage:\n"
">>> default_color = mapnik.Color(\"#0044cc\")\n"
">>> colorizer = mapnik.RasterColorizer(mapnik2.COLORIZER_LINEAR, default_color)\n"
">>> colorizer.add_stop(100, mapnik.Color(\"#123456\"))\n"
(arg("value")),
"Add a colorizer stop to the raster colorizer, using the default mode.\n"
"\n"
"Usage:\n"
">>> default_color = mapnik.Color(\"#0044cc\")\n"
">>> colorizer = mapnik.RasterColorizer(mapnik.COLORIZER_LINEAR, default_color)\n"
">>> colorizer.add_stop(100, mapnik.Color(\"#123456\"))\n"
)
.def("add_stop", add_stop4,
(arg("value")),
"Add a colorizer stop to the raster colorizer, using the default color.\n"
"\n"
"Usage:\n"
">>> default_color = mapnik.Color(\"#0044cc\")\n"
">>> colorizer = mapnik.RasterColorizer(mapnik2.COLORIZER_LINEAR, default_color)\n"
">>> colorizer.add_stop(100, mapnik2.COLORIZER_EXACT)\n"
(arg("value")),
"Add a colorizer stop to the raster colorizer, using the default color.\n"
"\n"
"Usage:\n"
">>> default_color = mapnik.Color(\"#0044cc\")\n"
">>> colorizer = mapnik.RasterColorizer(mapnik.COLORIZER_LINEAR, default_color)\n"
">>> colorizer.add_stop(100, mapnik.COLORIZER_EXACT)\n"
)
.def("add_stop", add_stop5,
(arg("value")),
"Add a colorizer stop to the raster colorizer.\n"
"\n"
"Usage:\n"
">>> default_color = mapnik.Color(\"#0044cc\")\n"
">>> colorizer = mapnik.RasterColorizer(mapnik2.COLORIZER_LINEAR, default_color)\n"
">>> colorizer.add_stop(100, mapnik.COLORIZER_DISCRETE, mapnik.Color(\"#112233\"))\n"
(arg("value")),
"Add a colorizer stop to the raster colorizer.\n"
"\n"
"Usage:\n"
">>> default_color = mapnik.Color(\"#0044cc\")\n"
">>> colorizer = mapnik.RasterColorizer(mapnik.COLORIZER_LINEAR, default_color)\n"
">>> colorizer.add_stop(100, mapnik.COLORIZER_DISCRETE, mapnik.Color(\"#112233\"))\n"
)
.def("get_color", &raster_colorizer::get_color,
"Get the color assigned to a certain value in raster data.\n"
"\n"
"Usage:\n"
">>> colorizer = mapnik.RasterColorizer()\n"
">>> color = mapnik.Color(\"#0044cc\")\n"
">>> colorizer.add_stop(0, mapnik2.COLORIZER_DISCRETE, mapnik.Color(\"#000000\"))\n"
">>> colorizer.add_stop(100, mapnik2.COLORIZER_DISCRETE, mapnik.Color(\"#0E0A06\"))\n"
">>> colorizer.get_color(50)\n"
"Color('#070503')\n"
.def("get_color", &raster_colorizer::get_color,
"Get the color assigned to a certain value in raster data.\n"
"\n"
"Usage:\n"
">>> colorizer = mapnik.RasterColorizer()\n"
">>> color = mapnik.Color(\"#0044cc\")\n"
">>> colorizer.add_stop(0, mapnik.COLORIZER_DISCRETE, mapnik.Color(\"#000000\"))\n"
">>> colorizer.add_stop(100, mapnik.COLORIZER_DISCRETE, mapnik.Color(\"#0E0A06\"))\n"
">>> colorizer.get_color(50)\n"
"Color('#070503')\n"
)
;

View file

@ -95,9 +95,9 @@ void export_style()
"Usage:\n"
">>> for r in m.find_style('style 1').rules:\n"
">>> print r\n"
"<mapnik2._mapnik2.Rule object at 0x100549910>\n"
"<mapnik2._mapnik2.Rule object at 0x100549980>\n"
)
"<mapnik._mapnik.Rule object at 0x100549910>\n"
"<mapnik._mapnik.Rule object at 0x100549980>\n"
)
.add_property("filter_mode",
&feature_type_style::get_filter_mode,
&feature_type_style::set_filter_mode,

View file

@ -59,6 +59,7 @@ namespace boost { namespace python {
PyObject * operator() (mapnik::value_null const& /*s*/) const
{
Py_INCREF(Py_None);
return Py_None;
}
};

View file

@ -41,7 +41,7 @@ if env['HAS_CAIRO']:
libraries = copy(env['LIBMAPNIK_LIBS'])
boost_program_options = 'boost_program_options%s' % env['BOOST_APPEND']
libraries.extend([boost_program_options,'mapnik2'])
libraries.extend([boost_program_options,'mapnik'])
rundemo = demo_env.Program('rundemo', source, LIBS=libraries, LINKFLAGS=env["CUSTOM_LDFLAGS"])
@ -50,4 +50,4 @@ Depends(rundemo, env.subst('../../src/%s' % env['MAPNIK_LIB_NAME']))
# we don't install this app because the datasource paths are relative
# and we're not going to install the sample data.
#env.Install(install_prefix + '/bin', rundemo)
#env.Alias('install', install_prefix + '/bin')
#env.Alias('install', install_prefix + '/bin')

View file

@ -43,7 +43,7 @@ int main ( int argc , char** argv)
{
if (argc != 2)
{
std::cout << "usage: ./rundemo <mapnik_install_dir>\nUsually /usr/local/lib/mapnik2\n";
std::cout << "usage: ./rundemo <mapnik_install_dir>\nUsually /usr/local/lib/mapnik\n";
std::cout << "Warning: ./rundemo looks for data in ../data/,\nTherefore must be run from within the demo/c++ folder.\n";
return EXIT_SUCCESS;
}

View file

@ -26,7 +26,7 @@
import sys
try:
import mapnik2
import mapnik
except:
print '\n\nThe mapnik library and python bindings must have been compiled and \
installed successfully before running this script.\n\n'
@ -41,11 +41,11 @@ except ImportError:
# Instanciate a map, giving it a width and height. Remember: the word "map" is
# reserved in Python! :)
m = mapnik2.Map(800,600,"+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")
m = mapnik.Map(800,600,"+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")
# Set its background colour. More on colours later ...
m.background = mapnik2.Color('white')
m.background = mapnik.Color('white')
# Now we can start adding layers, in stacking order (i.e. bottom layer first)
@ -66,9 +66,9 @@ m.background = mapnik2.Color('white')
# password='mypassword'
# table= TODO
provpoly_lyr = mapnik2.Layer('Provinces')
provpoly_lyr = mapnik.Layer('Provinces')
provpoly_lyr.srs = "+proj=lcc +ellps=GRS80 +lat_0=49 +lon_0=-95 +lat+1=49 +lat_2=77 +datum=NAD83 +units=m +no_defs"
provpoly_lyr.datasource = mapnik2.Shapefile(file='../data/boundaries', encoding='latin1')
provpoly_lyr.datasource = mapnik.Shapefile(file='../data/boundaries', encoding='latin1')
# We then define a style for the layer. A layer can have one or many styles.
# Styles are named, so they can be shared across different layers.
@ -78,18 +78,18 @@ provpoly_lyr.datasource = mapnik2.Shapefile(file='../data/boundaries', encoding=
# multiple styles in one layer is the same has having multiple layers.
# The paradigm is useful mostly as a convenience.
provpoly_style = mapnik2.Style()
provpoly_style = mapnik.Style()
# A Style needs one or more rules. A rule will normally consist of a filter
# for feature selection, and one or more symbolizers.
provpoly_rule_on = mapnik2.Rule()
provpoly_rule_on = mapnik.Rule()
# A Expression() allows the selection of features to which the symbology will
# be applied. More on Mapnik expressions can be found in Tutorial #2.
# A given feature can only match one filter per rule per style.
provpoly_rule_on.filter = mapnik2.Expression("[NAME_EN] = 'Ontario'")
provpoly_rule_on.filter = mapnik.Expression("[NAME_EN] = 'Ontario'")
# Here a symbolizer is defined. Available are:
# - LineSymbolizer(Color(),<width>)
@ -103,12 +103,12 @@ provpoly_rule_on.filter = mapnik2.Expression("[NAME_EN] = 'Ontario'")
# - Color(<string>) where <string> will be something like '#00FF00'
# or '#0f0' or 'green'
provpoly_rule_on.symbols.append(mapnik2.PolygonSymbolizer(mapnik2.Color(250, 190, 183)))
provpoly_rule_on.symbols.append(mapnik.PolygonSymbolizer(mapnik.Color(250, 190, 183)))
provpoly_style.rules.append(provpoly_rule_on)
provpoly_rule_qc = mapnik2.Rule()
provpoly_rule_qc.filter = mapnik2.Expression("[NOM_FR] = 'Québec'")
provpoly_rule_qc.symbols.append(mapnik2.PolygonSymbolizer(mapnik2.Color(217, 235, 203)))
provpoly_rule_qc = mapnik.Rule()
provpoly_rule_qc.filter = mapnik.Expression("[NOM_FR] = 'Québec'")
provpoly_rule_qc.symbols.append(mapnik.PolygonSymbolizer(mapnik.Color(217, 235, 203)))
provpoly_style.rules.append(provpoly_rule_qc)
# Add the style to the map, giving it a name. This is the name that will be
@ -131,14 +131,14 @@ m.layers.append(provpoly_lyr)
# A simple example ...
qcdrain_lyr = mapnik2.Layer('Quebec Hydrography')
qcdrain_lyr = mapnik.Layer('Quebec Hydrography')
qcdrain_lyr.srs = "+proj=lcc +ellps=GRS80 +lat_0=49 +lon_0=-95 +lat+1=49 +lat_2=77 +datum=NAD83 +units=m +no_defs"
qcdrain_lyr.datasource = mapnik2.Shapefile(file='../data/qcdrainage')
qcdrain_lyr.datasource = mapnik.Shapefile(file='../data/qcdrainage')
qcdrain_style = mapnik2.Style()
qcdrain_rule = mapnik2.Rule()
qcdrain_rule.filter = mapnik2.Expression('[HYC] = 8')
qcdrain_rule.symbols.append(mapnik2.PolygonSymbolizer(mapnik2.Color(153, 204, 255)))
qcdrain_style = mapnik.Style()
qcdrain_rule = mapnik.Rule()
qcdrain_rule.filter = mapnik.Expression('[HYC] = 8')
qcdrain_rule.symbols.append(mapnik.PolygonSymbolizer(mapnik.Color(153, 204, 255)))
qcdrain_style.rules.append(qcdrain_rule)
m.append_style('drainage', qcdrain_style)
@ -149,31 +149,31 @@ m.layers.append(qcdrain_lyr)
# attributes, and same desired style), so we're going to
# re-use the style defined in the above layer for the next one.
ondrain_lyr = mapnik2.Layer('Ontario Hydrography')
ondrain_lyr = mapnik.Layer('Ontario Hydrography')
ondrain_lyr.srs = "+proj=lcc +ellps=GRS80 +lat_0=49 +lon_0=-95 +lat+1=49 +lat_2=77 +datum=NAD83 +units=m +no_defs"
ondrain_lyr.datasource = mapnik2.Shapefile(file='../data/ontdrainage')
ondrain_lyr.datasource = mapnik.Shapefile(file='../data/ontdrainage')
ondrain_lyr.styles.append('drainage')
m.layers.append(ondrain_lyr)
# Provincial boundaries
provlines_lyr = mapnik2.Layer('Provincial borders')
provlines_lyr = mapnik.Layer('Provincial borders')
provlines_lyr.srs = "+proj=lcc +ellps=GRS80 +lat_0=49 +lon_0=-95 +lat+1=49 +lat_2=77 +datum=NAD83 +units=m +no_defs"
provlines_lyr.datasource = mapnik2.Shapefile(file='../data/boundaries_l')
provlines_lyr.datasource = mapnik.Shapefile(file='../data/boundaries_l')
# Here we define a "dash dot dot dash" pattern for the provincial boundaries.
provlines_stk = mapnik2.Stroke()
provlines_stk = mapnik.Stroke()
provlines_stk.add_dash(8, 4)
provlines_stk.add_dash(2, 2)
provlines_stk.add_dash(2, 2)
provlines_stk.color = mapnik2.Color('black')
provlines_stk.color = mapnik.Color('black')
provlines_stk.width = 1.0
provlines_style = mapnik2.Style()
provlines_rule = mapnik2.Rule()
provlines_rule.symbols.append(mapnik2.LineSymbolizer(provlines_stk))
provlines_style = mapnik.Style()
provlines_rule = mapnik.Rule()
provlines_rule.symbols.append(mapnik.LineSymbolizer(provlines_stk))
provlines_style.rules.append(provlines_rule)
m.append_style('provlines', provlines_style)
@ -182,22 +182,22 @@ m.layers.append(provlines_lyr)
# Roads 3 and 4 (The "grey" roads)
roads34_lyr = mapnik2.Layer('Roads')
roads34_lyr = mapnik.Layer('Roads')
roads34_lyr.srs = "+proj=lcc +ellps=GRS80 +lat_0=49 +lon_0=-95 +lat+1=49 +lat_2=77 +datum=NAD83 +units=m +no_defs"
# create roads datasource (we're going to re-use it later)
roads34_lyr.datasource = mapnik2.Shapefile(file='../data/roads')
roads34_lyr.datasource = mapnik.Shapefile(file='../data/roads')
roads34_style = mapnik2.Style()
roads34_rule = mapnik2.Rule()
roads34_rule.filter = mapnik2.Expression('([CLASS] = 3) or ([CLASS] = 4)')
roads34_style = mapnik.Style()
roads34_rule = mapnik.Rule()
roads34_rule.filter = mapnik.Expression('([CLASS] = 3) or ([CLASS] = 4)')
# With lines of a certain width, you can control how the ends
# are closed off using line_cap as below.
roads34_rule_stk = mapnik2.Stroke()
roads34_rule_stk.color = mapnik2.Color(171,158,137)
roads34_rule_stk.line_cap = mapnik2.line_cap.ROUND_CAP
roads34_rule_stk = mapnik.Stroke()
roads34_rule_stk.color = mapnik.Color(171,158,137)
roads34_rule_stk.line_cap = mapnik.line_cap.ROUND_CAP
# Available options are:
# line_cap: BUTT_CAP, SQUARE_CAP, ROUND_CAP
@ -207,7 +207,7 @@ roads34_rule_stk.line_cap = mapnik2.line_cap.ROUND_CAP
# can be set to a numerical value.
roads34_rule_stk.width = 2.0
roads34_rule.symbols.append(mapnik2.LineSymbolizer(roads34_rule_stk))
roads34_rule.symbols.append(mapnik.LineSymbolizer(roads34_rule_stk))
roads34_style.rules.append(roads34_rule)
m.append_style('smallroads', roads34_style)
@ -216,31 +216,31 @@ m.layers.append(roads34_lyr)
# Roads 2 (The thin yellow ones)
roads2_lyr = mapnik2.Layer('Roads')
roads2_lyr = mapnik.Layer('Roads')
roads2_lyr.srs = "+proj=lcc +ellps=GRS80 +lat_0=49 +lon_0=-95 +lat+1=49 +lat_2=77 +datum=NAD83 +units=m +no_defs"
# Just get a copy from roads34_lyr
roads2_lyr.datasource = roads34_lyr.datasource
roads2_style_1 = mapnik2.Style()
roads2_rule_1 = mapnik2.Rule()
roads2_rule_1.filter = mapnik2.Expression('[CLASS] = 2')
roads2_rule_stk_1 = mapnik2.Stroke()
roads2_rule_stk_1.color = mapnik2.Color(171,158,137)
roads2_rule_stk_1.line_cap = mapnik2.line_cap.ROUND_CAP
roads2_style_1 = mapnik.Style()
roads2_rule_1 = mapnik.Rule()
roads2_rule_1.filter = mapnik.Expression('[CLASS] = 2')
roads2_rule_stk_1 = mapnik.Stroke()
roads2_rule_stk_1.color = mapnik.Color(171,158,137)
roads2_rule_stk_1.line_cap = mapnik.line_cap.ROUND_CAP
roads2_rule_stk_1.width = 4.0
roads2_rule_1.symbols.append(mapnik2.LineSymbolizer(roads2_rule_stk_1))
roads2_rule_1.symbols.append(mapnik.LineSymbolizer(roads2_rule_stk_1))
roads2_style_1.rules.append(roads2_rule_1)
m.append_style('road-border', roads2_style_1)
roads2_style_2 = mapnik2.Style()
roads2_rule_2 = mapnik2.Rule()
roads2_rule_2.filter = mapnik2.Expression('[CLASS] = 2')
roads2_rule_stk_2 = mapnik2.Stroke()
roads2_rule_stk_2.color = mapnik2.Color(255,250,115)
roads2_rule_stk_2.line_cap = mapnik2.line_cap.ROUND_CAP
roads2_style_2 = mapnik.Style()
roads2_rule_2 = mapnik.Rule()
roads2_rule_2.filter = mapnik.Expression('[CLASS] = 2')
roads2_rule_stk_2 = mapnik.Stroke()
roads2_rule_stk_2.color = mapnik.Color(255,250,115)
roads2_rule_stk_2.line_cap = mapnik.line_cap.ROUND_CAP
roads2_rule_stk_2.width = 2.0
roads2_rule_2.symbols.append(mapnik2.LineSymbolizer(roads2_rule_stk_2))
roads2_rule_2.symbols.append(mapnik.LineSymbolizer(roads2_rule_stk_2))
roads2_style_2.rules.append(roads2_rule_2)
m.append_style('road-fill', roads2_style_2)
@ -252,29 +252,29 @@ m.layers.append(roads2_lyr)
# Roads 1 (The big orange ones, the highways)
roads1_lyr = mapnik2.Layer('Roads')
roads1_lyr = mapnik.Layer('Roads')
roads1_lyr.srs = "+proj=lcc +ellps=GRS80 +lat_0=49 +lon_0=-95 +lat+1=49 +lat_2=77 +datum=NAD83 +units=m +no_defs"
roads1_lyr.datasource = roads34_lyr.datasource
roads1_style_1 = mapnik2.Style()
roads1_rule_1 = mapnik2.Rule()
roads1_rule_1.filter = mapnik2.Expression('[CLASS] = 1')
roads1_rule_stk_1 = mapnik2.Stroke()
roads1_rule_stk_1.color = mapnik2.Color(188,149,28)
roads1_rule_stk_1.line_cap = mapnik2.line_cap.ROUND_CAP
roads1_style_1 = mapnik.Style()
roads1_rule_1 = mapnik.Rule()
roads1_rule_1.filter = mapnik.Expression('[CLASS] = 1')
roads1_rule_stk_1 = mapnik.Stroke()
roads1_rule_stk_1.color = mapnik.Color(188,149,28)
roads1_rule_stk_1.line_cap = mapnik.line_cap.ROUND_CAP
roads1_rule_stk_1.width = 7.0
roads1_rule_1.symbols.append(mapnik2.LineSymbolizer(roads1_rule_stk_1))
roads1_rule_1.symbols.append(mapnik.LineSymbolizer(roads1_rule_stk_1))
roads1_style_1.rules.append(roads1_rule_1)
m.append_style('highway-border', roads1_style_1)
roads1_style_2 = mapnik2.Style()
roads1_rule_2 = mapnik2.Rule()
roads1_rule_2.filter = mapnik2.Expression('[CLASS] = 1')
roads1_rule_stk_2 = mapnik2.Stroke()
roads1_rule_stk_2.color = mapnik2.Color(242,191,36)
roads1_rule_stk_2.line_cap = mapnik2.line_cap.ROUND_CAP
roads1_style_2 = mapnik.Style()
roads1_rule_2 = mapnik.Rule()
roads1_rule_2.filter = mapnik.Expression('[CLASS] = 1')
roads1_rule_stk_2 = mapnik.Stroke()
roads1_rule_stk_2.color = mapnik.Color(242,191,36)
roads1_rule_stk_2.line_cap = mapnik.line_cap.ROUND_CAP
roads1_rule_stk_2.width = 5.0
roads1_rule_2.symbols.append(mapnik2.LineSymbolizer(roads1_rule_stk_2))
roads1_rule_2.symbols.append(mapnik.LineSymbolizer(roads1_rule_stk_2))
roads1_style_2.rules.append(roads1_rule_2)
m.append_style('highway-fill', roads1_style_2)
@ -286,25 +286,25 @@ m.layers.append(roads1_lyr)
# Populated Places
popplaces_lyr = mapnik2.Layer('Populated Places')
popplaces_lyr = mapnik.Layer('Populated Places')
popplaces_lyr.srs = "+proj=lcc +ellps=GRS80 +lat_0=49 +lon_0=-95 +lat+1=49 +lat_2=77 +datum=NAD83 +units=m +no_defs"
popplaces_lyr.datasource = mapnik2.Shapefile(file='../data/popplaces',encoding='latin1')
popplaces_lyr.datasource = mapnik.Shapefile(file='../data/popplaces',encoding='latin1')
popplaces_style = mapnik2.Style()
popplaces_rule = mapnik2.Rule()
popplaces_style = mapnik.Style()
popplaces_rule = mapnik.Rule()
# And here we have a TextSymbolizer, used for labeling.
# The first parameter is the name of the attribute to use as the source of the
# text to label with. Then there is font size in points (I think?), and colour.
popplaces_text_symbolizer = mapnik2.TextSymbolizer(mapnik2.Expression("[GEONAME]"),
popplaces_text_symbolizer = mapnik.TextSymbolizer(mapnik.Expression("[GEONAME]"),
'DejaVu Sans Book',
10, mapnik2.Color('black'))
10, mapnik.Color('black'))
# We set a "halo" around the text, which looks like an outline if thin enough,
# or an outright background if large enough.
popplaces_text_symbolizer.label_placement= mapnik2.label_placement.POINT_PLACEMENT
popplaces_text_symbolizer.halo_fill = mapnik2.Color('white')
popplaces_text_symbolizer.label_placement= mapnik.label_placement.POINT_PLACEMENT
popplaces_text_symbolizer.halo_fill = mapnik.Color('white')
popplaces_text_symbolizer.halo_radius = 1
popplaces_text_symbolizer.avoid_edges = True
#popplaces_text_symbolizer.minimum_padding = 30
@ -320,11 +320,11 @@ m.layers.append(popplaces_lyr)
# Draw map
# Set the initial extent of the map in 'master' spherical Mercator projection
m.zoom_to_box(mapnik2.Box2d(-8024477.28459,5445190.38849,-7381388.20071,5662941.44855))
m.zoom_to_box(mapnik.Box2d(-8024477.28459,5445190.38849,-7381388.20071,5662941.44855))
# Render two maps, two PNGs, one JPEG.
im = mapnik2.Image(m.width,m.height)
mapnik2.render(m, im)
im = mapnik.Image(m.width,m.height)
mapnik.render(m, im)
# Save image to files
images_ = []
@ -348,37 +348,37 @@ im.save('demo_low.jpg', 'jpeg50')
images_.append('demo_low.jpg')
# Render cairo examples
if HAS_PYCAIRO_MODULE and mapnik2.has_pycairo():
if HAS_PYCAIRO_MODULE and mapnik.has_pycairo():
svg_surface = cairo.SVGSurface('demo.svg', m.width,m.height)
mapnik2.render(m, svg_surface)
mapnik.render(m, svg_surface)
svg_surface.finish()
images_.append('demo.svg')
pdf_surface = cairo.PDFSurface('demo.pdf', m.width,m.height)
mapnik2.render(m, pdf_surface)
mapnik.render(m, pdf_surface)
images_.append('demo.pdf')
pdf_surface.finish()
postscript_surface = cairo.PSSurface('demo.ps', m.width,m.height)
mapnik2.render(m, postscript_surface)
mapnik.render(m, postscript_surface)
images_.append('demo.ps')
postscript_surface.finish()
else:
print '\n\nPycairo not available...',
if mapnik2.has_cairo():
if mapnik.has_cairo():
print ' will render Cairo formats using alternative method'
mapnik2.render_to_file(m,'demo.pdf')
mapnik.render_to_file(m,'demo.pdf')
images_.append('demo.pdf')
mapnik2.render_to_file(m,'demo.ps')
mapnik.render_to_file(m,'demo.ps')
images_.append('demo.ps')
mapnik2.render_to_file(m,'demo.svg')
mapnik.render_to_file(m,'demo.svg')
images_.append('demo.svg')
mapnik2.render_to_file(m,'demo_cairo_rgb.png','RGB24')
mapnik.render_to_file(m,'demo_cairo_rgb.png','RGB24')
images_.append('demo_cairo_rgb.png')
mapnik2.render_to_file(m,'demo_cairo_argb.png','ARGB32')
mapnik.render_to_file(m,'demo_cairo_argb.png','ARGB32')
images_.append('demo_cairo_argb.png')
print "\n\n", len(images_), "maps have been rendered in the current directory:"
@ -388,4 +388,4 @@ for im_ in images_:
print "\n\nHave a look!\n\n"
mapnik2.save_map(m,"map.xml")
mapnik.save_map(m,"map.xml")

View file

@ -23,7 +23,7 @@ Import ('env')
import os
import platform
lib_dir = os.path.normpath(env['DESTDIR'] + '/' + env['PREFIX'] + '/' + env['LIBDIR_SCHEMA'] + '/mapnik2')
lib_dir = os.path.normpath(env['DESTDIR'] + '/' + env['PREFIX'] + '/' + env['LIBDIR_SCHEMA'] + '/mapnik')
fonts = 1
ini_template = '''

View file

@ -43,7 +43,7 @@ int main( int argc, char **argv )
// register input plug-ins
QString plugins_dir = settings.value("mapnik/plugins_dir",
QVariant("/usr/local/lib/mapnik2/input/")).toString();
QVariant("/usr/local/lib/mapnik/input/")).toString();
datasource_cache::instance()->register_datasources(plugins_dir.toStdString());
// register fonts
int count = settings.beginReadArray("mapnik/fonts");

View file

@ -11,7 +11,7 @@ INCLUDEPATH += /usr/X11/include/freetype2
INCLUDEPATH += .
QMAKE_CXXFLAGS +=' -DDARWIN -Wno-missing-field-initializers -ansi'
unix:LIBS = -L/usr/local/lib -L/usr/X11/lib -lmapnik2 -lfreetype
unix:LIBS = -L/usr/local/lib -L/usr/X11/lib -lmapnik -lfreetype
unix:LIBS += -lboost_system -licuuc -lboost_filesystem -lboost_regex
# Input

View file

@ -25,10 +25,15 @@
#ifndef MAPNIK_ATTRIBUTE_HPP
#define MAPNIK_ATTRIBUTE_HPP
// mapnik
#include <mapnik/value.hpp>
// stl
#include <string>
namespace mapnik {
static mapnik::value _null_value;
struct attribute
{
std::string name_;
@ -36,9 +41,15 @@ struct attribute
: name_(name) {}
template <typename V ,typename F>
V value(F const& f) const
V const& value(F const& f) const
{
return f[name_];
typedef typename F::const_iterator const_iterator;
const_iterator itr = f.find(name_);
if (itr != f.end())
{
return itr->second;
}
return _null_value;
}
std::string const& name() const { return name_;}
};

View file

@ -131,10 +131,12 @@ public:
}
protected:
void render_marker(const int x, const int y, marker &marker, const agg::trans_affine & mtx, double opacity=1.0);
void render_marker(const int x, const int y, marker &marker, const agg::trans_affine & mtx, double opacity=1.0, bool recenter=true);
Map const& m_;
Cairo::RefPtr<Cairo::Context> context_;
unsigned width_;
unsigned height_;
CoordTransform t_;
boost::shared_ptr<freetype_engine> font_engine_;
face_manager<freetype_engine> font_manager_;

View file

@ -0,0 +1 @@
#include <mapnik/filter_factory.hpp>

View file

@ -66,6 +66,7 @@ private:
std::map<std::string,value> props_;
public:
typedef std::map<std::string,value>::iterator iterator;
typedef std::map<std::string,value>::const_iterator const_iterator;
explicit feature(int id)
: properties(props_),
id_(id),
@ -146,7 +147,7 @@ public:
{
return props_;
}
iterator begin()
{
return props_.begin();
@ -156,7 +157,22 @@ public:
{
return props_.end();
}
const_iterator begin() const
{
return props_.begin();
}
const_iterator end() const
{
return props_.end();
}
const_iterator find(std::string const& key) const
{
return props_.find(key);
}
std::string to_string() const
{
std::stringstream ss;

View file

@ -77,7 +77,9 @@ public:
key_(key),
data_(width,height),
resolution_(resolution),
id_name_("__id__") {
painted_(false),
id_name_("__id__")
{
// this only works if each datasource's
// feature count starts at 1
f_keys_[0] = "";
@ -89,7 +91,8 @@ public:
key_(rhs.key_),
data_(rhs.data_),
resolution_(rhs.resolution_),
id_name_("__id__") {
painted_(rhs.painted_),
id_name_("__id__") {
f_keys_[0] = "";
}

View file

@ -434,7 +434,7 @@ private:
}
tries=0;
// ignore leaves and also nodes with small mean error and not excessive number of pixels
if ((cur_node->reduce_cost / cur_node->pixel_count + 1) * std::log(long(cur_node->pixel_count)) > 15
if (cur_node->pixel_count > 0 && (cur_node->reduce_cost / cur_node->pixel_count + 1) * std::log(long(cur_node->pixel_count)) > 15
&& cur_node->children_count > 0)
{
colors_--;

View file

@ -110,41 +110,81 @@ public:
* @param maxZoom The minimum zoom level to set
*/
void setMinZoom(double minZoom);
// forward compatibility with mapnik 2.1.x
void set_min_zoom(double minZoom)
{
setMinZoom(minZoom);
}
/*!
* @param maxZoom The maximum zoom level to set
*/
void setMaxZoom(double maxZoom);
// forward compatibility with mapnik 2.1.x
void set_max_zoom(double maxZoom)
{
setMinZoom(maxZoom);
}
/*!
* @return the minimum zoom level of the layer.
*/
double getMinZoom() const;
// forward compatibility with mapnik 2.1.x
double min_zoom() const
{
return getMinZoom();
}
/*!
* @return the maximum zoom level of the layer.
*/
double getMaxZoom() const;
// forward compatibility with mapnik 2.1.x
double max_zoom() const
{
return getMaxZoom();
}
/*!
* @brief Set whether this layer is active and will be rendered.
*/
void setActive(bool active);
// forward compatibility with mapnik 2.1.x
void set_active(bool active)
{
setActive(active);
}
/*!
* @return whether this layer is active and will be rendered.
*/
bool isActive() const;
// forward compatibility with mapnik 2.1.x
bool active() const
{
return isActive();
}
/*!
* @brief Set whether this layer is queryable.
*/
void setQueryable(bool queryable);
// forward compatibility with mapnik 2.1.x
void set_queryable(bool queryable)
{
setQueryable(queryable);
}
/*!
* @return whether this layer is queryable or not.
*/
bool isQueryable() const;
// forward compatibility with mapnik 2.1.x
bool queryable() const
{
return isQueryable();
}
/*!
* @brief Get the visability for a specific scale.
@ -159,6 +199,11 @@ public:
* scale < maxzoom + 1e-6
*/
bool isVisible(double scale) const;
// forward compatibility with mapnik 2.1.x
bool visible(double scale) const
{
return isVisible(scale);
}
/*!
* @param clear_cache Set whether this layer's labels are cached.

View file

@ -58,6 +58,8 @@ public:
explicit markers_symbolizer();
markers_symbolizer(path_expression_ptr filename);
markers_symbolizer(markers_symbolizer const& rhs);
void set_ignore_placement(bool ignore_placement);
bool get_ignore_placement() const;
void set_allow_overlap(bool overlap);
bool get_allow_overlap() const;
void set_spacing(double spacing);
@ -79,6 +81,7 @@ public:
private:
bool allow_overlap_;
bool ignore_placement_;
color fill_;
double spacing_;
double max_error_;

View file

@ -47,11 +47,22 @@ struct placement;
class metawriter_property_map
{
public:
typedef std::map<std::string, UnicodeString> property_map;
typedef property_map::const_iterator const_iterator;
metawriter_property_map() {}
UnicodeString const& operator[](std::string const& key) const;
UnicodeString& operator[](std::string const& key) {return m_[key];}
std::map<std::string, UnicodeString>::const_iterator find(std::string const& key) const
{
return m_.find(key);
}
std::map<std::string, UnicodeString>::const_iterator end() const
{
return m_.end();
}
private:
std::map<std::string, UnicodeString> m_;
property_map m_;
UnicodeString not_found_;
};

View file

@ -24,9 +24,31 @@
#ifndef MAPNIK_VERSION_HPP
#define MAPNIK_VERSION_HPP
#define MAPNIK_VERSION 200000
#define MAPNIK_VERSION_IS_RELEASE 0
#endif //MAPNIK_VERSION_HPP
#define MAPNIK_MAJOR_VERSION 2
#define MAPNIK_MINOR_VERSION 0
#define MAPNIK_PATCH_VERSION 3
#define MAPNIK_VERSION (MAPNIK_MAJOR_VERSION*100000) + (MAPNIK_MINOR_VERSION*100) + (MAPNIK_PATCH_VERSION)
#ifndef MAPNIK_STRINGIFY
#define MAPNIK_STRINGIFY(n) MAPNIK_STRINGIFY_HELPER(n)
#define MAPNIK_STRINGIFY_HELPER(n) #n
#endif
#if MAPNIK_VERSION_IS_RELEASE
# 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) "." \
MAPNIK_STRINGIFY(MAPNIK_MINOR_VERSION) "." \
MAPNIK_STRINGIFY(MAPNIK_PATCH_VERSION) "-pre"
#endif
#endif // MAPNIK_VERSION_HPP

View file

@ -36,16 +36,19 @@ gdal_src = Split(
plugin_env['LIBS'] = [env['PLUGINS']['gdal']['lib']]
# Link Library to Dependencies
plugin_env['LIBS'].append('mapnik2')
plugin_env['LIBS'].append('mapnik')
plugin_env['LIBS'].append(env['ICU_LIB_NAME'])
if env['HAS_BOOST_SYSTEM']:
plugin_env['LIBS'].append('boost_system%s' % env['BOOST_APPEND'])
if env['RUNTIME_LINK'] == 'static':
cmd = 'gdal-config --dep-libs'
plugin_env.ParseConfig(cmd)
input_plugin = plugin_env.SharedLibrary('../gdal', source=gdal_src, SHLIBPREFIX='', SHLIBSUFFIX='.input', LINKFLAGS=env['CUSTOM_LDFLAGS'])
# if the plugin links to libmapnik2 ensure it is built first
# if the plugin links to libmapnik ensure it is built first
Depends(input_plugin, env.subst('../../../src/%s' % env['MAPNIK_LIB_NAME']))
if 'uninstall' not in COMMAND_LINE_TARGETS:

View file

@ -36,14 +36,15 @@ geos_src = Split(
libraries = [env['PLUGINS']['geos']['lib']]
# Link Library to Dependencies
libraries.append('mapnik2')
libraries.append('mapnik')
libraries.append(env['ICU_LIB_NAME'])
libraries.append('boost_system%s' % env['BOOST_APPEND'])
if env['HAS_BOOST_SYSTEM']:
libraries.append('boost_system%s' % env['BOOST_APPEND'])
libraries.append('boost_filesystem%s' % env['BOOST_APPEND'])
input_plugin = plugin_env.SharedLibrary('../geos', source=geos_src, SHLIBPREFIX='', SHLIBSUFFIX='.input', LIBS=libraries, LINKFLAGS=env['CUSTOM_LDFLAGS'])
# if the plugin links to libmapnik2 ensure it is built first
# if the plugin links to libmapnik ensure it is built first
Depends(input_plugin, env.subst('../../../src/%s' % env['MAPNIK_LIB_NAME']))
if 'uninstall' not in COMMAND_LINE_TARGETS:

View file

@ -26,6 +26,7 @@
// geos
#include <geos_c.h>
#include <cstdlib>
class geos_feature_ptr
{
@ -77,7 +78,10 @@ public:
~geos_wkb_ptr ()
{
if (data_ != NULL)
GEOSFree(data_);
{
// We use std::free here instead of GEOSFree(data_) to support geos 3.1.0
std::free(data_);
}
}
bool is_valid() const

View file

@ -34,13 +34,16 @@ kismet_src = Split(
libraries = []
# Link Library to Dependencies
libraries.append('mapnik2')
libraries.append('mapnik')
libraries.append(env['ICU_LIB_NAME'])
libraries.append('boost_thread%s' % env['BOOST_APPEND'])
if env['HAS_BOOST_SYSTEM']:
libraries.append('boost_system%s' % env['BOOST_APPEND'])
input_plugin = plugin_env.SharedLibrary('../kismet', source=kismet_src, SHLIBPREFIX='', SHLIBSUFFIX='.input', LIBS=libraries, LINKFLAGS=env['CUSTOM_LDFLAGS'])
# if the plugin links to libmapnik2 ensure it is built first
# if the plugin links to libmapnik ensure it is built first
Depends(input_plugin, env.subst('../../../src/%s' % env['MAPNIK_LIB_NAME']))
if 'uninstall' not in COMMAND_LINE_TARGETS:

View file

@ -36,12 +36,14 @@ occi_src = Split(
)
libraries = [ 'occi', 'ociei' ]
libraries.append('mapnik2')
libraries.append('mapnik')
libraries.append(env['ICU_LIB_NAME'])
if env['HAS_BOOST_SYSTEM']:
libraries.append('boost_system%s' % env['BOOST_APPEND'])
input_plugin = plugin_env.SharedLibrary('../occi', source=occi_src, SHLIBPREFIX='', SHLIBSUFFIX='.input', LIBS=libraries, LINKFLAGS=env['CUSTOM_LDFLAGS'])
# if the plugin links to libmapnik2 ensure it is built first
# if the plugin links to libmapnik ensure it is built first
Depends(input_plugin, env.subst('../../../src/%s' % env['MAPNIK_LIB_NAME']))
if 'uninstall' not in COMMAND_LINE_TARGETS:

View file

@ -38,18 +38,26 @@ ogr_src = Split(
plugin_env['LIBS'] = [env['PLUGINS']['ogr']['lib']]
# Link Library to Dependencies
plugin_env['LIBS'].append('mapnik2')
plugin_env['LIBS'].append('mapnik')
plugin_env['LIBS'].append(env['ICU_LIB_NAME'])
plugin_env['LIBS'].append('boost_system%s' % env['BOOST_APPEND'])
if env['HAS_BOOST_SYSTEM']:
plugin_env['LIBS'].append('boost_system%s' % env['BOOST_APPEND'])
plugin_env['LIBS'].append('boost_filesystem%s' % env['BOOST_APPEND'])
if env['RUNTIME_LINK'] == 'static':
cmd = 'gdal-config --dep-libs'
plugin_env.ParseConfig(cmd)
if env.get('BOOST_LIB_VERSION_FROM_HEADER'):
boost_version_from_header = int(env['BOOST_LIB_VERSION_FROM_HEADER'].split('_')[1])
if boost_version_from_header < 46:
# avoid ubuntu issue with boost interprocess:
# https://github.com/mapnik/mapnik/issues/1082
plugin_env.Append(CXXFLAGS = '-fpermissive')
input_plugin = plugin_env.SharedLibrary('../ogr', source=ogr_src, SHLIBPREFIX='', SHLIBSUFFIX='.input', LINKFLAGS=env['CUSTOM_LDFLAGS'])
# if the plugin links to libmapnik2 ensure it is built first
# if the plugin links to libmapnik ensure it is built first
Depends(input_plugin, env.subst('../../../src/%s' % env['MAPNIK_LIB_NAME']))
if 'uninstall' not in COMMAND_LINE_TARGETS:

View file

@ -169,11 +169,12 @@ void ogr_datasource::bind() const
if (!layer_)
{
std::string s("OGR Plugin: ");
if (layer_by_name) s += "cannot find layer by name '" + *layer_by_name;
else if (layer_by_index) s += "cannot find layer by index number '" + *layer_by_index;
s += "' in dataset '" + dataset_name_ + "'";
throw datasource_exception(s);
std::ostringstream s;
s << "OGR Plugin: ";
if (layer_by_name) s << "cannot find layer by name '" << *layer_by_name;
else if (layer_by_index) s << "cannot find layer by index number '" << *layer_by_index;
s << "' in dataset '" << dataset_name_ << "'";
throw datasource_exception(s.str());
}
// initialize envelope

View file

@ -38,12 +38,14 @@ osm_src = Split(
libraries = [ 'xml2' ]
libraries.append('curl')
libraries.append('mapnik2')
libraries.append('mapnik')
libraries.append(env['ICU_LIB_NAME'])
if env['HAS_BOOST_SYSTEM']:
libraries.append('boost_system%s' % env['BOOST_APPEND'])
input_plugin = plugin_env.SharedLibrary('../osm', source=osm_src, SHLIBPREFIX='', SHLIBSUFFIX='.input', LIBS=libraries, LINKFLAGS=env['CUSTOM_LDFLAGS'])
# if the plugin links to libmapnik2 ensure it is built first
# if the plugin links to libmapnik ensure it is built first
Depends(input_plugin, env.subst('../../../src/%s' % env['MAPNIK_LIB_NAME']))
if 'uninstall' not in COMMAND_LINE_TARGETS:

View file

@ -32,17 +32,28 @@ postgis_src = Split(
"""
)
libraries = ['pq']
# clear out and rebuild libs
plugin_env['LIBS'] = ['pq']
# Link Library to Dependencies
libraries.append('mapnik2')
libraries.append(env['ICU_LIB_NAME'])
plugin_env['LIBS'].append('mapnik')
plugin_env['LIBS'].append(env['ICU_LIB_NAME'])
if env['THREADING'] == 'multi':
libraries.append('boost_thread%s' % env['BOOST_APPEND'])
plugin_env['LIBS'].append('boost_thread%s' % env['BOOST_APPEND'])
input_plugin = plugin_env.SharedLibrary('../postgis', source=postgis_src, SHLIBPREFIX='', SHLIBSUFFIX='.input', LIBS=libraries, LINKFLAGS=env['CUSTOM_LDFLAGS'])
if env['HAS_BOOST_SYSTEM']:
plugin_env['LIBS'].append('boost_system%s' % env['BOOST_APPEND'])
# if the plugin links to libmapnik2 ensure it is built first
if env['RUNTIME_LINK'] == 'static':
#cmd = 'pg_config --libs'
#plugin_env.ParseConfig(cmd)
# pg_config does not seem to report correct deps of libpq
# so resort to hardcoding for now
plugin_env['LIBS'].extend(['ldap','pam','ssl','crypto','krb5'])
input_plugin = plugin_env.SharedLibrary('../postgis', source=postgis_src, SHLIBPREFIX='', SHLIBSUFFIX='.input', LINKFLAGS=env['CUSTOM_LDFLAGS'])
# if the plugin links to libmapnik ensure it is built first
Depends(input_plugin, env.subst('../../../src/%s' % env['MAPNIK_LIB_NAME']))
if 'uninstall' not in COMMAND_LINE_TARGETS:

View file

@ -83,8 +83,6 @@ postgis_datasource::postgis_datasource(parameters const& params, bool bind)
persist_connection_(*params_.get<mapnik::boolean>("persist_connection",true)),
extent_from_subquery_(*params_.get<mapnik::boolean>("extent_from_subquery",false)),
// params below are for testing purposes only (will likely be removed at any time)
force2d_(*params_.get<mapnik::boolean>("force_2d",false)),
st_(*params_.get<mapnik::boolean>("st_prefix",false)),
intersect_min_scale_(*params_.get<int>("intersect_min_scale",0)),
intersect_max_scale_(*params_.get<int>("intersect_max_scale",0))
//show_queries_(*params_.get<mapnik::boolean>("show_queries",false))
@ -302,6 +300,7 @@ void postgis_datasource::bind() const
case 1042: // bpchar
case 1043: // varchar
case 25: // text
case 705: // literal
desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::String));
break;
default: // should not get here
@ -358,7 +357,7 @@ std::string postgis_datasource::sql_bbox(box2d<double> const& env) const
{
std::ostringstream b;
if (srid_ > 0)
b << "SetSRID(";
b << "ST_SetSRID(";
b << "'BOX3D(";
b << std::setprecision(16);
b << env.minx() << " " << env.miny() << ",";
@ -495,13 +494,7 @@ featureset_ptr postgis_datasource::features(const query& q) const
}
std::ostringstream s;
s << "SELECT ";
if (st_)
s << "ST_";
if (force2d_)
s << "AsBinary(ST_Force_2D(\"" << geometryColumn_ << "\")) AS geom";
else
s << "AsBinary(\"" << geometryColumn_ << "\") AS geom";
s << "SELECT ST_AsBinary(\"" << geometryColumn_ << "\") AS geom";
if (!key_field_.empty())
mapnik::quote_attr(s,key_field_);
@ -571,13 +564,7 @@ featureset_ptr postgis_datasource::features_at_point(coord2d const& pt) const
}
s << "SELECT ";
if (st_)
s << "ST_";
if (force2d_)
s << "AsBinary(ST_Force_2D(\"" << geometryColumn_ << "\")) AS geom";
else
s << "AsBinary(\"" << geometryColumn_ << "\") AS geom";
s << "SELECT ST_AsBinary(\"" << geometryColumn_ << "\") AS geom";
if (!key_field_.empty())
mapnik::quote_attr(s,key_field_);

View file

@ -75,8 +75,6 @@ class postgis_datasource : public datasource
bool persist_connection_;
bool extent_from_subquery_;
// params below are for testing purposes only (will likely be removed at any time)
bool force2d_;
bool st_;
int intersect_min_scale_;
int intersect_max_scale_;
//bool show_queries_;

View file

@ -152,7 +152,7 @@ feature_ptr postgis_featureset::next()
float8net(val,buf);
boost::put(*feature,name,val);
}
else if (oid==25 || oid==1043) // text or varchar
else if (oid==25 || oid==1043 || oid==705 ) // text or varchar or literal
{
UnicodeString ustr = tr_->transcode(buf);
boost::put(*feature,name,ustr);

View file

@ -35,14 +35,15 @@ raster_src = Split(
libraries = []
# Link Library to Dependencies
libraries.append('mapnik2')
libraries.append('mapnik')
libraries.append(env['ICU_LIB_NAME'])
libraries.append('boost_system%s' % env['BOOST_APPEND'])
if env['HAS_BOOST_SYSTEM']:
libraries.append('boost_system%s' % env['BOOST_APPEND'])
libraries.append('boost_filesystem%s' % env['BOOST_APPEND'])
input_plugin = plugin_env.SharedLibrary('../raster', source=raster_src, SHLIBPREFIX='', SHLIBSUFFIX='.input', LIBS=libraries, LINKFLAGS=env['CUSTOM_LDFLAGS'])
# if the plugin links to libmapnik2 ensure it is built first
# if the plugin links to libmapnik ensure it is built first
Depends(input_plugin, env.subst('../../../src/%s' % env['MAPNIK_LIB_NAME']))
if 'uninstall' not in COMMAND_LINE_TARGETS:

View file

@ -35,14 +35,15 @@ rasterlite_src = Split(
libraries = [env['PLUGINS']['rasterlite']['lib']]
# Link Library to Dependencies
libraries.append('mapnik2')
libraries.append('mapnik')
libraries.append(env['ICU_LIB_NAME'])
libraries.append('boost_system%s' % env['BOOST_APPEND'])
if env['HAS_BOOST_SYSTEM']:
libraries.append('boost_system%s' % env['BOOST_APPEND'])
libraries.append('boost_filesystem%s' % env['BOOST_APPEND'])
input_plugin = plugin_env.SharedLibrary('../rasterlite', source=rasterlite_src, SHLIBPREFIX='', SHLIBSUFFIX='.input', LIBS=libraries, LINKFLAGS=env['CUSTOM_LDFLAGS'])
# if the plugin links to libmapnik2 ensure it is built first
# if the plugin links to libmapnik ensure it is built first
Depends(input_plugin, env.subst('../../../src/%s' % env['MAPNIK_LIB_NAME']))
if 'uninstall' not in COMMAND_LINE_TARGETS:

View file

@ -39,17 +39,25 @@ shape_src = Split(
libraries = []
# Link Library to Dependencies
libraries.append('mapnik2')
libraries.append('mapnik')
libraries.append(env['ICU_LIB_NAME'])
libraries.append('boost_system%s' % env['BOOST_APPEND'])
if env['HAS_BOOST_SYSTEM']:
libraries.append('boost_system%s' % env['BOOST_APPEND'])
libraries.append('boost_filesystem%s' % env['BOOST_APPEND'])
if env['SHAPE_MEMORY_MAPPED_FILE']:
plugin_env.Append(CXXFLAGS = '-DSHAPE_MEMORY_MAPPED_FILE')
if env.get('BOOST_LIB_VERSION_FROM_HEADER'):
boost_version_from_header = int(env['BOOST_LIB_VERSION_FROM_HEADER'].split('_')[1])
if boost_version_from_header < 46:
# avoid ubuntu issue with boost interprocess:
# https://github.com/mapnik/mapnik/issues/1082
plugin_env.Append(CXXFLAGS = '-fpermissive')
input_plugin = plugin_env.SharedLibrary('../shape', SHLIBSUFFIX='.input', source=shape_src, SHLIBPREFIX='', LIBS = libraries, LINKFLAGS=env['CUSTOM_LDFLAGS'])
# if the plugin links to libmapnik2 ensure it is built first
# if the plugin links to libmapnik ensure it is built first
Depends(input_plugin, env.subst('../../../src/%s' % env['MAPNIK_LIB_NAME']))
if 'uninstall' not in COMMAND_LINE_TARGETS:

View file

@ -35,14 +35,16 @@ sqlite_src = Split(
libraries = [ 'sqlite3' ]
# Link Library to Dependencies
libraries.append('mapnik2')
libraries.append('mapnik')
libraries.append(env['ICU_LIB_NAME'])
libraries.append('boost_system%s' % env['BOOST_APPEND'])
if env['HAS_BOOST_SYSTEM']:
libraries.append('boost_system%s' % env['BOOST_APPEND'])
libraries.append('boost_filesystem%s' % env['BOOST_APPEND'])
input_plugin = plugin_env.SharedLibrary('../sqlite', source=sqlite_src, SHLIBPREFIX='', SHLIBSUFFIX='.input', LIBS=libraries, LINKFLAGS=env['CUSTOM_LDFLAGS'])
# if the plugin links to libmapnik2 ensure it is built first
# if the plugin links to libmapnik ensure it is built first
Depends(input_plugin, env.subst('../../../src/%s' % env['MAPNIK_LIB_NAME']))
if 'uninstall' not in COMMAND_LINE_TARGETS:

View file

@ -142,27 +142,26 @@ public:
sqlite_connection (const std::string& file)
: db_(0)
{
// sqlite3_open_v2 is available earlier but
// shared cache not available until >= 3.6.18
#if SQLITE_VERSION_NUMBER >= 3006018
int rc = sqlite3_enable_shared_cache(1);
#if SQLITE_VERSION_NUMBER >= 3005000
int mode = SQLITE_OPEN_READWRITE;
#if SQLITE_VERSION_NUMBER >= 3006018
// shared cache flag not available until >= 3.6.18
mode |= SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_SHAREDCACHE;
#endif
const int rc = sqlite3_open_v2 (file.c_str(), &db_, mode, 0);
#else
#warning "Mapnik's sqlite plugin is compiling against a version of sqlite older than 3.5.x which may make rendering slow..."
const int rc = sqlite3_open (file.c_str(), &db_);
#endif
if (rc != SQLITE_OK)
{
throw mapnik::datasource_exception (sqlite3_errmsg (db_));
}
int mode = SQLITE_OPEN_READWRITE | SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_SHAREDCACHE;
if (sqlite3_open_v2 (file.c_str(), &db_, mode, NULL))
#else
#warning "Mapnik's sqlite plugin is compiling against a version of sqlite older than 3.6.18 which may make rendering slow..."
if (sqlite3_open (file.c_str(), &db_))
#endif
{
std::ostringstream s;
s << "Sqlite Plugin: ";
throw mapnik::datasource_exception (sqlite3_errmsg (db_));
s << "Sqlite Plugin: " << sqlite3_errmsg (db_);
throw mapnik::datasource_exception (s.str());
}
//sqlite3_enable_load_extension(db_, 1);
sqlite3_busy_timeout(db_,5000);
}
~sqlite_connection ()

View file

@ -31,7 +31,7 @@ the middle of any map tile and display a "hello world!" label if used like:
Or used in python like:
from mapnik2 import *
from mapnik import *
m = Map(600,400)
m.background = Color('white')
s = Style()

View file

@ -22,7 +22,7 @@ Import ('env')
# main SConstruct file where configuration happens
# plugins can go anywhere, and be registered in custom locations by Mapnik
# but the standard location is '/usr/local/lib/mapnik2/input'
# but the standard location is '/usr/local/lib/mapnik/input'
install_dest = env['MAPNIK_INPUT_PLUGINS_DEST']
# clone the environment here
@ -42,7 +42,7 @@ plugin_sources = Split(
# directly link to
libraries = [ '' ] # eg 'libfoo'
libraries.append('mapnik2')
libraries.append('mapnik')
# link libicuuc, but ICU_LIB_NAME is used custom builds of icu can
# have different library names like osx which offers /usr/lib/libicucore.dylib
libraries.append(env['ICU_LIB_NAME'])

View file

@ -142,7 +142,9 @@ void agg_renderer<T>::process(markers_symbolizer const& sym,
unsigned s_a=col.alpha();
double w = sym.get_width();
double h = sym.get_height();
double rx = w;
double ry = h;
arrow arrow_;
box2d<double> extent;
@ -196,7 +198,7 @@ void agg_renderer<T>::process(markers_symbolizer const& sym,
if (sym.get_allow_overlap() ||
detector_.has_placement(label_ext))
{
agg::ellipse c(x, y, w, h);
agg::ellipse c(x, y, rx, ry);
marker.concat_path(c);
ras_ptr->add_path(marker);
ren.color(agg::rgba8(r, g, b, int(a*sym.get_opacity())));
@ -215,7 +217,8 @@ void agg_renderer<T>::process(markers_symbolizer const& sym,
ren.color(agg::rgba8(s_r, s_g, s_b, int(s_a*stroke_.get_opacity())));
agg::render_scanlines(*ras_ptr, sl_line, ren);
}
detector_.insert(label_ext);
if (!sym.get_ignore_placement())
detector_.insert(label_ext);
if (writer.first) writer.first->add_box(label_ext, feature, t_, writer.second);
}
}
@ -239,7 +242,7 @@ void agg_renderer<T>::process(markers_symbolizer const& sym,
if (marker_type == ELLIPSE)
{
// todo proper bbox - this is buggy
agg::ellipse c(x_t, y_t, w, h);
agg::ellipse c(x_t, y_t, rx, ry);
marker.concat_path(c);
agg::trans_affine matrix;
matrix *= agg::trans_affine_translation(-x_t,-y_t);

View file

@ -135,7 +135,8 @@ void agg_renderer<T>::process(shield_symbolizer const& sym,
ren.set_halo_radius(sym.get_halo_radius() * scale_factor_);
ren.set_opacity(sym.get_text_opacity());
placement_finder<label_collision_detector4> finder(detector_);
box2d<double> dims(0,0,width_,height_);
placement_finder<label_collision_detector4> finder(detector_,dims);
string_info info(text);
@ -214,7 +215,7 @@ void agg_renderer<T>::process(shield_symbolizer const& sym,
{
render_marker(px,py,**marker,tr,sym.get_opacity());
box2d<double> dim = ren.prepare_glyphs(&text_placement.placements[0]);
ren.prepare_glyphs(&text_placement.placements[0]);
ren.render(x,y);
detector_.insert(label_ext);
finder.update_detector(text_placement);
@ -253,7 +254,7 @@ void agg_renderer<T>::process(shield_symbolizer const& sym,
render_marker(px,py,**marker,tr,sym.get_opacity());
box2d<double> dim = ren.prepare_glyphs(&text_placement.placements[ii]);
ren.prepare_glyphs(&text_placement.placements[ii]);
ren.render(x,y);
if (writer.first) writer.first->add_box(label_ext, feature, t_, writer.second);
}

View file

@ -55,7 +55,10 @@ filesystem = 'boost_filesystem%s' % env['BOOST_APPEND']
regex = 'boost_regex%s' % env['BOOST_APPEND']
# clear out and re-set libs for this env
lib_env['LIBS'] = ['freetype','ltdl','png','tiff','z','jpeg','proj',env['ICU_LIB_NAME'],filesystem,regex]
lib_env['LIBS'] = ['freetype','ltdl','png','tiff','z','proj',env['ICU_LIB_NAME'],filesystem,regex]
if env['JPEG']:
lib_env['LIBS'].append('jpeg')
if len(env['EXTRA_FREETYPE_LIBS']):
lib_env['LIBS'].extend(copy(env['EXTRA_FREETYPE_LIBS']))
@ -77,11 +80,15 @@ if not env['RUNTIME_LINK'] == 'static':
else:
lib_env['LIBS'].append([lib for lib in env['LIBS'] if lib.startswith('agg')])
if env['RUNTIME_LINK'] == 'static':
if 'icuuc' in env['ICU_LIB_NAME']:
lib_env['LIBS'].append('icudata')
lib_env['LIBS'].append('icui18n')
if env['PLATFORM'] == 'Darwin':
mapnik_libname = 'libmapnik2.dylib'
mapnik_libname = 'libmapnik.dylib'
else:
mapnik_libname = 'libmapnik2.so.' + ("%d.%d" % (ABI_VERSION[0],ABI_VERSION[1]))
mapnik_libname = 'libmapnik.so.' + ("%d.%d" % (int(ABI_VERSION[0]),int(ABI_VERSION[1])))
if env['PLATFORM'] == 'Darwin':
if env['FULL_LIB_PATH']:
@ -89,7 +96,7 @@ if env['PLATFORM'] == 'Darwin':
else:
lib_path = mapnik_libname
mapnik_lib_link_flag += ' -Wl,-install_name,%s' % lib_path
_d = {'version':env['MAPNIK_VERSION_STRING']}
_d = {'version':env['MAPNIK_VERSION_STRING'].replace('-pre','')}
mapnik_lib_link_flag += ' -current_version %(version)s -compatibility_version %(version)s' % _d
elif env['PLATFORM'] == 'SunOS':
if env['CXX'].startswith('CC'):
@ -204,6 +211,20 @@ if env['LIBTOOL_SUPPORTS_ADVISE']:
else:
source.insert(0,'datasource_cache.cpp')
if env.get('BOOST_LIB_VERSION_FROM_HEADER'):
boost_version_from_header = int(env['BOOST_LIB_VERSION_FROM_HEADER'].split('_')[1])
if boost_version_from_header < 46:
# avoid ubuntu issue with boost interprocess:
# https://github.com/mapnik/mapnik/issues/1001
env4 = lib_env.Clone()
env4.Append(CXXFLAGS = '-fpermissive')
cpp ='mapped_memory_cache.cpp'
source.remove(cpp)
if env['LINKING'] == 'static':
source.insert(0,env4.StaticObject(cpp))
else:
source.insert(0,env4.SharedObject(cpp))
if env['JPEG']:
source += Split(
"""
@ -293,9 +314,9 @@ else:
linkflags = mapnik_lib_link_flag
if env['LINKING'] == 'static':
mapnik = lib_env.StaticLibrary('mapnik2', source, LINKFLAGS=linkflags)
mapnik = lib_env.StaticLibrary('mapnik', source, LINKFLAGS=linkflags)
else:
mapnik = lib_env.SharedLibrary('mapnik2', source, LINKFLAGS=linkflags)
mapnik = lib_env.SharedLibrary('mapnik', source, LINKFLAGS=linkflags)
# cache library values for other builds to use
env['LIBMAPNIK_LIBS'] = copy(lib_env['LIBS'])
@ -313,7 +334,7 @@ if env['PLATFORM'] != 'Darwin':
major, minor, micro = ABI_VERSION
soFile = "%s.%d.%d.%d" % (os.path.basename(str(mapnik[0])), major, minor, micro)
soFile = "%s.%d.%d.%d" % (os.path.basename(str(mapnik[0])), int(major), int(minor), int(micro))
target = os.path.join(env['MAPNIK_LIB_BASE_DEST'], soFile)
if 'uninstall' not in COMMAND_LINE_TARGETS:
@ -324,7 +345,7 @@ if env['PLATFORM'] != 'Darwin':
# Install symlinks
target1 = os.path.join(env['MAPNIK_LIB_BASE_DEST'], "%s.%d.%d" % (os.path.basename(str(mapnik[0])),major, minor))
target1 = os.path.join(env['MAPNIK_LIB_BASE_DEST'], "%s.%d.%d" % (os.path.basename(str(mapnik[0])),int(major), int(minor)))
target2 = os.path.join(env['MAPNIK_LIB_BASE_DEST'], os.path.basename(str(mapnik[0])))
if 'uninstall' not in COMMAND_LINE_TARGETS:
if 'install' in COMMAND_LINE_TARGETS:

View file

@ -40,6 +40,9 @@
#include <mapnik/warp.hpp>
#include <mapnik/config.hpp>
#include "agg_path_storage.h" // for markers_symbolizer
#include "agg_ellipse.h" // for markers_symbolizer
// cairo
#include <cairomm/context.h>
#include <cairomm/surface.h>
@ -657,6 +660,8 @@ private:
cairo_renderer_base::cairo_renderer_base(Map const& m, Cairo::RefPtr<Cairo::Context> const& context, unsigned offset_x, unsigned offset_y)
: m_(m),
context_(context),
width_(m.width()),
height_(m.height()),
t_(m.width(),m.height(),m.get_current_extent(),offset_x,offset_y),
font_engine_(new freetype_engine()),
font_manager_(*font_engine_),
@ -908,7 +913,7 @@ void cairo_renderer_base::process(line_symbolizer const& sym,
}
}
void cairo_renderer_base::render_marker(const int x, const int y, marker &marker, const agg::trans_affine & tr, double opacity)
void cairo_renderer_base::render_marker(const int x, const int y, marker &marker, const agg::trans_affine & tr, double opacity, bool recenter)
{
cairo_context context(context_);
@ -917,15 +922,21 @@ void cairo_renderer_base::render_marker(const int x, const int y, marker &marker
box2d<double> bbox;
bbox = (*marker.get_vector_data())->bounding_box();
coord<double,2> c = bbox.center();
// center the svg marker on '0,0'
agg::trans_affine mtx = agg::trans_affine_translation(-c.x,-c.y);
// apply symbol transformation to get to map space
mtx *= tr;
// render the marker at the center of the marker box
mtx.translate(x+0.5 * marker.width(), y+0.5 * marker.height());
agg::trans_affine mtx = tr;
if (recenter)
{
coord<double,2> c = bbox.center();
// center the svg marker on '0,0'
mtx = agg::trans_affine_translation(-c.x,-c.y);
// apply symbol transformation to get to map space
mtx *= tr;
// render the marker at the center of the marker box
mtx.translate(x+0.5 * marker.width(), y+0.5 * marker.height());
}
typedef coord_transform2<CoordTransform,geometry_type> path_type;
agg::trans_affine transform;
mapnik::path_ptr vmarker = *marker.get_vector_data();
agg::pod_bvector<path_attributes> const & attributes_ = vmarker->attributes();
@ -937,10 +948,10 @@ void cairo_renderer_base::render_marker(const int x, const int y, marker &marker
context.save();
agg::trans_affine transform = attr.transform;
transform = attr.transform;
transform *= mtx;
if (transform.is_valid() && !transform.is_identity())
if (/*transform.is_valid() &&*/ !transform.is_identity())
{
double m[6];
transform.store_to(m);
@ -1136,7 +1147,8 @@ void cairo_renderer_base::process(shield_symbolizer const& sym,
cairo_context context(context_);
string_info info(text);
placement_finder<label_collision_detector4> finder(detector_);
box2d<double> dims(0,0,width_,height_);
placement_finder<label_collision_detector4> finder(detector_,dims);
faces->set_pixel_sizes(placement_options->text_size);
faces->get_string_info(info);
@ -1423,34 +1435,236 @@ void cairo_renderer_base::process(markers_symbolizer const& sym,
Feature const& feature,
proj_transform const& prj_trans)
{
typedef coord_transform2<CoordTransform,geometry_type> path_type;
arrow arrow_;
cairo_context context(context_);
color const& fill_ = sym.get_fill();
context.set_color(fill_.red(), fill_.green(), fill_.blue(), fill_.alpha());
double scale_factor_(1);
for (unsigned i = 0; i < feature.num_geometries(); ++i)
typedef coord_transform2<CoordTransform,mapnik::geometry_type> path_type;
agg::trans_affine tr;
boost::array<double,6> const& m = sym.get_transform();
tr.load_from(&m[0]);
// TODO - use this?
//tr = agg::trans_affine_scaling(scale_factor_) * tr;
std::string filename = path_processor_type::evaluate(*sym.get_filename(), feature);
marker_placement_e placement_method = sym.get_marker_placement();
marker_type_e marker_type = sym.get_marker_type();
metawriter_with_properties writer = sym.get_metawriter();
if (!filename.empty())
{
geometry_type const& geom = feature.get_geometry(i);
if (geom.num_points() > 1)
boost::optional<marker_ptr> mark = mapnik::marker_cache::instance()->find(filename, true);
if (mark && *mark)
{
path_type path(t_, geom, prj_trans);
if (!(*mark)->is_vector()) {
std::clog << "### Warning only svg markers are supported in the markers_symbolizer\n";
return;
}
boost::optional<path_ptr> marker = (*mark)->get_vector_data();
box2d<double> const& bbox = (*marker)->bounding_box();
double x1 = bbox.minx();
double y1 = bbox.miny();
double x2 = bbox.maxx();
double y2 = bbox.maxy();
double w = (*mark)->width();
double h = (*mark)->height();
markers_placement<path_type, label_collision_detector4> placement(path, arrow_.extent(), detector_, sym.get_spacing(), sym.get_max_error(), sym.get_allow_overlap());
agg::trans_affine recenter = agg::trans_affine_translation(-0.5*(x1+x2),-0.5*(y1+y2));
tr.transform(&x1,&y1);
tr.transform(&x2,&y2);
box2d<double> extent(x1,y1,x2,y2);
using namespace mapnik::svg;
double x, y, angle;
while (placement.get_point(&x, &y, &angle)) {
Cairo::Matrix matrix = Cairo::rotation_matrix(angle) * Cairo::translation_matrix(x,y) ;
context.set_matrix(matrix);
context.add_path(arrow_);
for (unsigned i=0; i<feature.num_geometries(); ++i)
{
geometry_type const& geom = feature.get_geometry(i);
// TODO - merge this code with point_symbolizer rendering
if (placement_method == MARKER_POINT_PLACEMENT || geom.num_points() <= 1)
{
double x;
double y;
double z=0;
geom.label_interior_position(&x, &y);
prj_trans.backward(x,y,z);
t_.forward(&x,&y);
extent.re_center(x,y);
if (sym.get_allow_overlap() ||
detector_.has_placement(extent))
{
render_marker(x - 0.5 * w, y - 0.5 * h,**mark, tr, sym.get_opacity());
// TODO - impl this for markers?
//if (!sym.get_ignore_placement())
// detector_.insert(label_ext);
metawriter_with_properties writer = sym.get_metawriter();
if (writer.first) writer.first->add_box(extent, feature, t_, writer.second);
}
}
else
{
path_type path(t_,geom,prj_trans);
markers_placement<path_type, label_collision_detector4> placement(path, extent, detector_,
sym.get_spacing() * scale_factor_,
sym.get_max_error(),
sym.get_allow_overlap());
double x, y, angle;
while (placement.get_point(&x, &y, &angle))
{
agg::trans_affine matrix = recenter * tr * agg::trans_affine_rotation(angle) * agg::trans_affine_translation(x, y);
render_marker(x - 0.5 * w, y - 0.5 * h, **mark, matrix, sym.get_opacity(),false);
if (writer.first)
//writer.first->add_box(label_ext, feature, t_, writer.second);
std::clog << "### Warning metawriter not yet supported for LINE placement\n";
}
}
context.fill();
}
}
}
else
{
color const& fill_ = sym.get_fill();
stroke const& stroke_ = sym.get_stroke();
color const& col = stroke_.get_color();
double strk_width = stroke_.get_width();
double w = sym.get_width();
double h = sym.get_height();
double rx = w;
double ry = h;
arrow arrow_;
box2d<double> extent;
double dx = w + (2*strk_width);
double dy = h + (2*strk_width);
if (marker_type == ARROW)
{
extent = arrow_.extent();
double x1 = extent.minx();
double y1 = extent.miny();
double x2 = extent.maxx();
double y2 = extent.maxy();
tr.transform(&x1,&y1);
tr.transform(&x2,&y2);
extent.init(x1,y1,x2,y2);
}
else
{
double x1 = -1 *(dx);
double y1 = -1 *(dy);
double x2 = dx;
double y2 = dy;
tr.transform(&x1,&y1);
tr.transform(&x2,&y2);
extent.init(x1,y1,x2,y2);
}
double x;
double y;
double z=0;
agg::path_storage marker;
for (unsigned i=0; i<feature.num_geometries(); ++i)
{
geometry_type const& geom = feature.get_geometry(i);
if (placement_method == MARKER_POINT_PLACEMENT || geom.num_points() <= 1)
{
geom.label_position(&x,&y);
prj_trans.backward(x,y,z);
t_.forward(&x,&y);
int px = int(floor(x - 0.5 * dx));
int py = int(floor(y - 0.5 * dy));
box2d<double> label_ext (px, py, px + dx +1, py + dy +1);
if (sym.get_allow_overlap() ||
detector_.has_placement(label_ext))
{
agg::ellipse c(x, y, rx, ry);
marker.concat_path(c);
context.set_color(fill_,sym.get_opacity());
context.add_agg_path(marker);
context.fill();
if (strk_width)
{
//context.restore();
context.set_color(col,stroke_.get_opacity());
context.set_line_width(stroke_.get_width());
if (stroke_.has_dash())
{
context.set_dash(stroke_.get_dash_array());
}
context.add_agg_path(marker);
context.stroke();
}
if (!sym.get_ignore_placement())
detector_.insert(label_ext);
if (writer.first) writer.first->add_box(label_ext, feature, t_, writer.second);
}
}
else
{
if (marker_type == ARROW)
marker.concat_path(arrow_);
path_type path(t_,geom,prj_trans);
markers_placement<path_type, label_collision_detector4> placement(path, extent, detector_,
sym.get_spacing() * scale_factor_,
sym.get_max_error(),
sym.get_allow_overlap());
double x_t, y_t, angle;
while (placement.get_point(&x_t, &y_t, &angle))
{
agg::trans_affine matrix;
if (marker_type == ELLIPSE)
{
agg::ellipse c(x_t, y_t, rx, ry);
marker.concat_path(c);
agg::trans_affine matrix;
matrix *= agg::trans_affine_translation(-x_t,-y_t);
matrix *= agg::trans_affine_rotation(angle);
matrix *= agg::trans_affine_translation(x_t,y_t);
marker.transform(matrix);
}
else
{
matrix = tr * agg::trans_affine_rotation(angle) * agg::trans_affine_translation(x_t, y_t);
}
// TODO
if (writer.first)
//writer.first->add_box(label_ext, feature, t_, writer.second);
std::clog << "### Warning metawriter not yet supported for LINE placement\n";
agg::conv_transform<agg::path_storage, agg::trans_affine> trans(marker, matrix);
context.set_color(fill_,sym.get_opacity());
context.add_agg_path(trans);
context.fill();
if (strk_width)
{
context.set_color(col,stroke_.get_opacity());
context.set_line_width(stroke_.get_width());
if (stroke_.has_dash())
{
context.set_dash(stroke_.get_dash_array());
}
context.add_agg_path(trans);
context.stroke();
}
}
}
}
context.fill();
}
}
void cairo_renderer_base::process(glyph_symbolizer const& sym,
Feature const& feature,
proj_transform const& prj_trans)
@ -1566,7 +1780,8 @@ void cairo_renderer_base::process(text_symbolizer const& sym,
faces->set_pixel_sizes(placement_options->text_size);
faces->get_string_info(info);
placement_finder<label_collision_detector4> finder(detector_);
box2d<double> dims(0,0,width_,height_);
placement_finder<label_collision_detector4> finder(detector_,dims);
metawriter_with_properties writer = sym.get_metawriter();

View file

@ -25,6 +25,7 @@
#include <mapnik/graphics.hpp>
#include <mapnik/image_util.hpp>
#include <mapnik/global.hpp>
#include <mapnik/color.hpp>
// cairo
#ifdef HAVE_CAIRO
@ -117,9 +118,23 @@ void image_32::set_grayscale_to_alpha()
}
}
void image_32::set_color_to_alpha(const color& /*c*/)
void image_32::set_color_to_alpha(const color& c)
{
// TODO - function to set all pixels to a % alpha based on distance to a given color
for (unsigned y = 0; y < height_; ++y)
{
unsigned int* row_from = data_.getRow(y);
for (unsigned x = 0; x < width_; ++x)
{
unsigned rgba = row_from[x];
unsigned r = rgba & 0xff;
unsigned g = (rgba >> 8 ) & 0xff;
unsigned b = (rgba >> 16) & 0xff;
if (r == c.red() && g == c.green() && b == c.blue())
{
row_from[x] = 0;
}
}
}
}
void image_32::set_alpha(float opacity)

View file

@ -145,7 +145,10 @@ void grid_renderer<T>::process(markers_symbolizer const& sym,
w = sym.get_width()/res;
h = sym.get_height()/res;
}
double rx = w;
double ry = h;
arrow arrow_;
box2d<double> extent;
@ -193,7 +196,7 @@ void grid_renderer<T>::process(markers_symbolizer const& sym,
if (sym.get_allow_overlap() ||
detector_.has_placement(label_ext))
{
agg::ellipse c(x, y, w, h);
agg::ellipse c(x, y, rx, ry);
agg::path_storage marker;
marker.concat_path(c);
ras_ptr->add_path(marker);
@ -230,7 +233,7 @@ void grid_renderer<T>::process(markers_symbolizer const& sym,
if (marker_type == ELLIPSE)
{
// todo proper bbox - this is buggy
agg::ellipse c(x_t, y_t, w, h);
agg::ellipse c(x_t, y_t, rx, ry);
marker.concat_path(c);
agg::trans_affine matrix;
matrix *= agg::trans_affine_translation(-x_t,-y_t);

View file

@ -116,7 +116,8 @@ void grid_renderer<T>::process(shield_symbolizer const& sym,
ren.set_halo_radius(sym.get_halo_radius() * scale_factor_);
ren.set_opacity(sym.get_text_opacity());
placement_finder<label_collision_detector4> finder(detector_);
box2d<double> dims(0,0,width_,height_);
placement_finder<label_collision_detector4> finder(detector_,dims);
string_info info(text);
@ -196,7 +197,7 @@ void grid_renderer<T>::process(shield_symbolizer const& sym,
{
render_marker(feature,pixmap_.get_resolution(),px,py,**marker,tr,sym.get_opacity());
box2d<double> dim = ren.prepare_glyphs(&text_placement.placements[0]);
ren.prepare_glyphs(&text_placement.placements[0]);
ren.render_id(feature.id(),x,y,2);
detector_.insert(label_ext);
finder.update_detector(text_placement);
@ -226,7 +227,7 @@ void grid_renderer<T>::process(shield_symbolizer const& sym,
render_marker(feature,pixmap_.get_resolution(),px,py,**marker,tr,sym.get_opacity());
box2d<double> dim = ren.prepare_glyphs(&text_placement.placements[ii]);
ren.prepare_glyphs(&text_placement.placements[ii]);
ren.render_id(feature.id(),x,y,2);
}
finder.update_detector(text_placement);

View file

@ -83,7 +83,6 @@ void grid_renderer<T>::process(text_symbolizer const& sym,
ren.set_halo_radius(sym.get_halo_radius() * scale_factor_);
ren.set_opacity(sym.get_text_opacity());
// /pixmap_.get_resolution() ?
box2d<double> dims(0,0,width_,height_);
placement_finder<label_collision_detector4> finder(detector_,dims);

View file

@ -0,0 +1,67 @@
/*****************************************************************************
*
* 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
*
*****************************************************************************/
// TODO https://github.com/mapnik/mapnik/issues/1658
#include <boost/version.hpp>
#if BOOST_VERSION >= 105200
#define BOOST_SPIRIT_USE_PHOENIX_V3
#endif
// mapnik
#include <mapnik/json/feature_collection_parser.hpp>
#include <mapnik/json/feature_collection_grammar.hpp>
// boost
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/support_multi_pass.hpp>
namespace mapnik { namespace json {
#if BOOST_VERSION >= 104700
template <typename Iterator>
feature_collection_parser<Iterator>::feature_collection_parser(mapnik::context_ptr const& ctx, mapnik::transcoder const& tr)
: grammar_(new feature_collection_grammar<iterator_type,feature_type>(ctx,tr)) {}
template <typename Iterator>
feature_collection_parser<Iterator>::~feature_collection_parser() {}
#endif
template <typename Iterator>
bool feature_collection_parser<Iterator>::parse(iterator_type first, iterator_type last, std::vector<mapnik::feature_ptr> & features)
{
#if BOOST_VERSION >= 104700
using namespace boost::spirit;
return qi::phrase_parse(first, last, *grammar_, standard_wide::space, features);
#else
std::ostringstream s;
s << BOOST_VERSION/100000 << "." << BOOST_VERSION/100 % 1000 << "." << BOOST_VERSION % 100;
throw std::runtime_error("mapnik::feature_collection_parser::parse() requires at least boost 1.47 while your build was compiled against boost " + s.str());
return false;
#endif
}
template class feature_collection_parser<std::string::const_iterator> ;
template class feature_collection_parser<boost::spirit::multi_pass<std::istreambuf_iterator<char> > >;
}}

View file

@ -389,6 +389,10 @@ void map_parser::parse_map_include( Map & map, ptree const & include )
}
datasource_templates_[name] = params;
}
else if (v.first == "Parameters")
{
// do not throw in order to support Mapnik 2.1.x stylesheets
}
else if (v.first != "<xmlcomment>" &&
v.first != "<xmlattr>")
{
@ -975,6 +979,7 @@ void map_parser::parse_markers_symbolizer( rule & rule, ptree const & sym )
//s << "file,opacity,spacing,max-error,allow-overlap,placement,";
s << "file,base,transform,fill,opacity,"
<< "spacing,max-error,allow-overlap,"
<< "ignore-placement,"
<< "width,height,placement,marker-type,"
<< "stroke,stroke-width,stroke-opacity,stroke-linejoin,"
<< "stroke-linecap,stroke-dashoffset,stroke-dasharray,"
@ -1047,7 +1052,9 @@ void map_parser::parse_markers_symbolizer( rule & rule, ptree const & sym )
optional<double> max_error = get_opt_attr<double>(sym, "max-error");
if (max_error) symbol.set_max_error(*max_error);
optional<boolean> allow_overlap = get_opt_attr<boolean>(sym, "allow-overlap");
optional<boolean> ignore_placement = get_opt_attr<boolean>(sym, "ignore-placement");
if (allow_overlap) symbol.set_allow_overlap(*allow_overlap);
if (ignore_placement) symbol.set_ignore_placement(*ignore_placement);
optional<double> w = get_opt_attr<double>(sym, "width");
optional<double> h = get_opt_attr<double>(sym, "height");

View file

@ -47,6 +47,7 @@ markers_symbolizer::markers_symbolizer()
: symbolizer_with_image(path_expression_ptr(new path_expression)),
symbolizer_base(),
allow_overlap_(false),
ignore_placement_(false),
fill_(color(0,0,255)),
spacing_(100.0),
max_error_(0.2),
@ -60,6 +61,7 @@ markers_symbolizer::markers_symbolizer(path_expression_ptr filename)
: symbolizer_with_image(filename),
symbolizer_base(),
allow_overlap_(false),
ignore_placement_(false),
fill_(color(0,0,255)),
spacing_(100.0),
max_error_(0.2),
@ -73,15 +75,26 @@ markers_symbolizer::markers_symbolizer(markers_symbolizer const& rhs)
: symbolizer_with_image(rhs),
symbolizer_base(rhs),
allow_overlap_(rhs.allow_overlap_),
fill_(rhs.fill_),
spacing_(rhs.spacing_),
ignore_placement_(rhs.ignore_placement_),
fill_(rhs.fill_),
spacing_(rhs.spacing_),
max_error_(rhs.max_error_),
width_(rhs.width_),
height_(rhs.height_),
stroke_(rhs.stroke_),
marker_p_(rhs.marker_p_),
marker_type_(rhs.marker_type_) {}
void markers_symbolizer::set_ignore_placement(bool ignore_placement)
{
ignore_placement_ = ignore_placement;
}
bool markers_symbolizer::get_ignore_placement() const
{
return ignore_placement_;
}
void markers_symbolizer::set_allow_overlap(bool overlap)
{
allow_overlap_ = overlap;

View file

@ -35,10 +35,11 @@ bool rgba::mean_sort_cmp::operator() (const rgba& x, const rgba& y) const
int t2 = (int)y.a + y.r + y.g + y.b;
if (t1 != t2) return t1 < t2;
return (((int)x.a - y.a) >> 24) +
(((int)x.r - y.r) >> 16) +
(((int)x.g - y.g) >> 8) +
(((int)x.b - y.b));
// https://github.com/mapnik/mapnik/issues/1087
if (x.a != y.a) return x.a < y.a;
if (x.r != y.r) return x.r < y.r;
if (x.g != y.g) return x.g < y.g;
return x.b < y.b;
}
std::size_t rgba::hash_func::operator()(rgba const& p) const

View file

@ -135,12 +135,17 @@ void projection::init()
mutex::scoped_lock lock(mutex_);
#endif
#if PJ_VERSION >= 480
proj_ctx_=pj_ctx_alloc();
proj_=pj_init_plus_ctx(proj_ctx_, params_.c_str());
proj_ctx_ = pj_ctx_alloc();
proj_ = pj_init_plus_ctx(proj_ctx_, params_.c_str());
if (!proj_)
{
if (proj_ctx_) pj_ctx_free(proj_ctx_);
throw proj_init_error(params_);
}
#else
proj_=pj_init_plus(params_.c_str());
#endif
proj_ = pj_init_plus(params_.c_str());
if (!proj_) throw proj_init_error(params_);
#endif
is_geographic_ = pj_is_latlong(proj_) ? true : false;
}

View file

@ -261,6 +261,10 @@ public:
{
set_attr( sym_node, "allow-overlap", sym.get_allow_overlap() );
}
if (sym.get_ignore_placement() != dfl.get_ignore_placement() || explicit_defaults_)
{
set_attr( sym_node, "ignore-placement", sym.get_ignore_placement() );
}
if (sym.get_spacing() != dfl.get_spacing() || explicit_defaults_)
{
set_attr( sym_node, "spacing", sym.get_spacing() );
@ -609,7 +613,7 @@ private:
}
if ( strk.dash_offset() != dfl.dash_offset() || explicit_defaults_ )
{
set_attr( node, "stroke-dash-offset", strk.dash_offset());
set_attr( node, "stroke-dashoffset", strk.dash_offset());
}
if ( ! strk.get_dash_array().empty() )
{

View file

@ -403,7 +403,7 @@ void svg_parser::parse_path(xmlTextReaderPtr reader)
if (!mapnik::svg::parse_path((const char*) value, path_))
{
std::runtime_error("can't parse PATH\n");
throw std::runtime_error("can't parse PATH\n");
}
path_.end_path();
}

View file

@ -81,8 +81,8 @@ public:
#ifndef MAPNIK_BIG_ENDIAN
needSwap_=byteOrder_?wkbXDR:wkbNDR;
#else
needSwap_=byteOrder_?wkbNDR:wkbXDR;
#endif
needSwap_=byteOrder_?wkbNDR:wkbXDR;
#endif
}
~wkb_reader() {}
@ -215,7 +215,7 @@ private:
void read_multipoint(boost::ptr_vector<geometry_type> & paths)
{
int num_points = read_integer();
for (int i=0;i<num_points;++i)
for (int i=0;i<num_points;++i)
{
pos_+=5;
read_point(paths);
@ -225,8 +225,8 @@ private:
void read_multipoint_2(boost::ptr_vector<geometry_type> & paths)
{
geometry_type * pt = new geometry_type(MultiPoint);
int num_points = read_integer();
for (int i=0;i<num_points;++i)
int num_points = read_integer();
for (int i=0;i<num_points;++i)
{
pos_+=5;
double x = read_double();
@ -238,17 +238,20 @@ private:
void read_linestring(boost::ptr_vector<geometry_type> & paths)
{
geometry_type * line = new geometry_type(LineString);
int num_points=read_integer();
CoordinateArray ar(num_points);
read_coords(ar);
line->set_capacity(num_points);
line->move_to(ar[0].x,ar[0].y);
for (int i=1;i<num_points;++i)
if (num_points > 0)
{
line->line_to(ar[i].x,ar[i].y);
geometry_type * line = new geometry_type(LineString);
CoordinateArray ar(num_points);
read_coords(ar);
line->set_capacity(num_points);
line->move_to(ar[0].x,ar[0].y);
for (int i=1;i<num_points;++i)
{
line->line_to(ar[i].x,ar[i].y);
}
paths.push_back(line);
}
paths.push_back(line);
}
void read_multilinestring(boost::ptr_vector<geometry_type> & paths)
@ -263,45 +266,51 @@ private:
void read_multilinestring_2(boost::ptr_vector<geometry_type> & paths)
{
geometry_type * line = new geometry_type(MultiLineString);
int num_lines=read_integer();
unsigned capacity = 0;
for (int i=0;i<num_lines;++i)
if (num_lines > 0)
{
pos_+=5;
int num_points=read_integer();
capacity+=num_points;
CoordinateArray ar(num_points);
read_coords(ar);
line->set_capacity(capacity);
line->move_to(ar[0].x,ar[0].y);
for (int j=1;j<num_points;++j)
{
line->line_to(ar[j].x,ar[j].y);
}
geometry_type * line = new geometry_type(MultiLineString);
unsigned capacity = 0;
for (int i=0;i<num_lines;++i)
{
pos_+=5;
int num_points=read_integer();
capacity+=num_points;
CoordinateArray ar(num_points);
read_coords(ar);
line->set_capacity(capacity);
line->move_to(ar[0].x,ar[0].y);
for (int j=1;j<num_points;++j)
{
line->line_to(ar[j].x,ar[j].y);
}
}
paths.push_back(line);
}
paths.push_back(line);
}
void read_polygon(boost::ptr_vector<geometry_type> & paths)
{
geometry_type * poly = new geometry_type(Polygon);
int num_rings=read_integer();
unsigned capacity = 0;
for (int i=0;i<num_rings;++i)
if (num_rings > 0)
{
int num_points=read_integer();
capacity+=num_points;
CoordinateArray ar(num_points);
read_coords(ar);
poly->set_capacity(capacity);
poly->move_to(ar[0].x,ar[0].y);
for (int j=1;j<num_points;++j)
geometry_type * poly = new geometry_type(Polygon);
unsigned capacity = 0;
for (int i=0;i<num_rings;++i)
{
poly->line_to(ar[j].x,ar[j].y);
int num_points=read_integer();
capacity+=num_points;
CoordinateArray ar(num_points);
read_coords(ar);
poly->set_capacity(capacity);
poly->move_to(ar[0].x,ar[0].y);
for (int j=1;j<num_points;++j)
{
poly->line_to(ar[j].x,ar[j].y);
}
}
paths.push_back(poly);
}
paths.push_back(poly);
}
void read_multipolygon(boost::ptr_vector<geometry_type> & paths)
@ -316,29 +325,35 @@ private:
void read_multipolygon_2(boost::ptr_vector<geometry_type> & paths)
{
geometry_type * poly = new geometry_type(MultiPolygon);
int num_polys=read_integer();
unsigned capacity = 0;
for (int i=0;i<num_polys;++i)
if (num_polys > 0)
{
pos_+=5;
int num_rings=read_integer();
for (int r=0;r<num_rings;++r)
geometry_type * poly = new geometry_type(MultiPolygon);
unsigned capacity = 0;
for (int i=0;i<num_polys;++i)
{
int num_points=read_integer();
capacity += num_points;
CoordinateArray ar(num_points);
read_coords(ar);
poly->set_capacity(capacity);
poly->move_to(ar[0].x,ar[0].y);
for (int j=1;j<num_points;++j)
pos_+=5;
int num_rings=read_integer();
for (int r=0;r<num_rings;++r)
{
poly->line_to(ar[j].x,ar[j].y);
int num_points=read_integer();
if (num_points > 0)
{
capacity += num_points;
CoordinateArray ar(num_points);
read_coords(ar);
poly->set_capacity(capacity);
poly->move_to(ar[0].x,ar[0].y);
for (int j=1;j<num_points;++j)
{
poly->line_to(ar[j].x,ar[j].y);
}
poly->line_to(ar[0].x,ar[0].y);
}
}
poly->line_to(ar[0].x,ar[0].y);
}
paths.push_back(poly);
}
paths.push_back(poly);
}
void read_collection(boost::ptr_vector<geometry_type> & paths)

View file

@ -9,7 +9,7 @@ test_env = env.Clone()
headers = env['CPPPATH']
libraries = copy(env['LIBMAPNIK_LIBS'])
libraries.append('mapnik2')
libraries.append('mapnik')
for cpp_test in glob.glob('*_test.cpp'):
test_program = test_env.Program(cpp_test.replace('.cpp',''), [cpp_test], CPPPATH=headers, LIBS=libraries, LINKFLAGS=env['CUSTOM_LDFLAGS'])

View file

@ -9,7 +9,7 @@ filesystem = 'boost_filesystem%s' % env['BOOST_APPEND']
system = 'boost_system%s' % env['BOOST_APPEND']
regex = 'boost_regex%s' % env['BOOST_APPEND']
libraries = [filesystem, 'mapnik2']
libraries = [filesystem, 'mapnik']
if env['PLATFORM'] == 'Darwin':
libraries.append(env['ICU_LIB_NAME'])

View file

@ -1,7 +1,7 @@
#!/usr/bin/env python
import os
import mapnik2
import mapnik
from nose.tools import *
from utilities import execution_path,Todo
@ -11,13 +11,13 @@ def setup():
os.chdir(execution_path('.'))
def _pycairo_surface(type,sym):
if mapnik2.has_pycairo():
if mapnik.has_pycairo():
import cairo
test_cairo_file = 'test.%s' % type
m = mapnik2.Map(256,256)
mapnik2.load_map(m,'../data/good_maps/%s_symbolizer.xml' % sym)
m = mapnik.Map(256,256)
mapnik.load_map(m,'../data/good_maps/%s_symbolizer.xml' % sym)
surface = getattr(cairo,'%sSurface' % type.upper())(test_cairo_file, m.width,m.height)
mapnik2.render(m, surface)
mapnik.render(m, surface)
surface.finish()
if os.path.exists(test_cairo_file):

View file

@ -3,7 +3,7 @@
from nose.tools import *
from utilities import execution_path
import os, mapnik2
import os, mapnik
def setup():
# All of the paths used are relative, if we run the tests
@ -11,36 +11,36 @@ def setup():
os.chdir(execution_path('.'))
def test_field_listing():
lyr = mapnik2.Layer('test')
lyr.datasource = mapnik2.Shapefile(file='../data/shp/poly.shp')
lyr = mapnik.Layer('test')
lyr.datasource = mapnik.Shapefile(file='../data/shp/poly.shp')
fields = lyr.datasource.fields()
eq_(fields, ['AREA', 'EAS_ID', 'PRFEDEA'])
def test_total_feature_count_shp():
lyr = mapnik2.Layer('test')
lyr.datasource = mapnik2.Shapefile(file='../data/shp/poly.shp')
lyr = mapnik.Layer('test')
lyr.datasource = mapnik.Shapefile(file='../data/shp/poly.shp')
features = lyr.datasource.all_features()
num_feats = len(features)
eq_(num_feats, 10)
def test_total_feature_count_json():
lyr = mapnik2.Layer('test')
lyr.datasource = mapnik2.Ogr(file='../data/json/points.json',layer_by_index=0)
lyr = mapnik.Layer('test')
lyr.datasource = mapnik.Ogr(file='../data/json/points.json',layer_by_index=0)
features = lyr.datasource.all_features()
num_feats = len(features)
eq_(num_feats, 5)
def test_reading_json_from_string():
json = open('../data/json/points.json','r').read()
lyr = mapnik2.Layer('test')
lyr.datasource = mapnik2.Ogr(file=json,layer_by_index=0)
lyr = mapnik.Layer('test')
lyr.datasource = mapnik.Ogr(file=json,layer_by_index=0)
features = lyr.datasource.all_features()
num_feats = len(features)
eq_(num_feats, 5)
def test_feature_envelope():
lyr = mapnik2.Layer('test')
lyr.datasource = mapnik2.Shapefile(file='../data/shp/poly.shp')
lyr = mapnik.Layer('test')
lyr.datasource = mapnik.Shapefile(file='../data/shp/poly.shp')
features = lyr.datasource.all_features()
for feat in features:
env = feat.envelope()
@ -50,8 +50,8 @@ def test_feature_envelope():
eq_(intersects, True)
def test_feature_attributes():
lyr = mapnik2.Layer('test')
lyr.datasource = mapnik2.Shapefile(file='../data/shp/poly.shp')
lyr = mapnik.Layer('test')
lyr.datasource = mapnik.Shapefile(file='../data/shp/poly.shp')
features = lyr.datasource.all_features()
feat = features[0]
attrs = {'PRFEDEA': u'35043411', 'EAS_ID': 168, 'AREA': 215229.266}
@ -67,8 +67,8 @@ def test_hit_grid():
""" encode a list of strings with run-length compression """
return ["%d:%s" % (len(list(group)), name) for name, group in groupby(l)]
m = mapnik2.Map(256,256);
mapnik2.load_map(m,'../data/good_maps/agg_poly_gamma_map.xml');
m = mapnik.Map(256,256);
mapnik.load_map(m,'../data/good_maps/agg_poly_gamma_map.xml');
m.zoom_all()
join_field = 'NAME'
fg = [] # feature grid

View file

@ -4,7 +4,7 @@ from nose.tools import *
from utilities import execution_path, Todo
import os, sys, glob, mapnik2
import os, sys, glob, mapnik
def setup():
# All of the paths used are relative, if we run the tests
@ -12,8 +12,8 @@ def setup():
os.chdir(execution_path('.'))
def compare_shape_between_mapnik_and_ogr(shapefile,query=None):
ds1 = mapnik2.Ogr(file=shapefile,layer_by_index=0)
ds2 = mapnik2.Shapefile(file=shapefile)
ds1 = mapnik.Ogr(file=shapefile,layer_by_index=0)
ds2 = mapnik.Shapefile(file=shapefile)
if query:
fs1 = ds1.features(query)
fs2 = ds2.features(query)
@ -44,8 +44,8 @@ def test_shapefile_polygon_featureset_id():
def test_shapefile_polygon_feature_query_id():
bbox = (15523428.2632, 4110477.6323, -11218494.8310, 7495720.7404)
query = mapnik2.Query(mapnik2.Box2d(*bbox))
ds = mapnik2.Ogr(file='../data/shp/world_merc.shp',layer_by_index=0)
query = mapnik.Query(mapnik.Box2d(*bbox))
ds = mapnik.Ogr(file='../data/shp/world_merc.shp',layer_by_index=0)
for fld in ds.fields():
query.add_property_name(fld)
compare_shape_between_mapnik_and_ogr('../data/shp/world_merc.shp',query)
@ -55,11 +55,11 @@ def test_feature_hit_count():
# results in different results between shp and ogr!
#bbox = (-14284551.8434, 2074195.1992, -7474929.8687, 8140237.7628)
bbox = (1113194.91,4512803.085,2226389.82,6739192.905)
query = mapnik2.Query(mapnik2.Box2d(*bbox))
ds1 = mapnik2.Ogr(file='../data/shp/world_merc.shp',layer_by_index=0)
query = mapnik.Query(mapnik.Box2d(*bbox))
ds1 = mapnik.Ogr(file='../data/shp/world_merc.shp',layer_by_index=0)
for fld in ds1.fields():
query.add_property_name(fld)
ds2 = mapnik2.Shapefile(file='../data/shp/world_merc.shp')
ds2 = mapnik.Shapefile(file='../data/shp/world_merc.shp')
count1 = len(ds1.features(query).features)
count2 = len(ds2.features(query).features)
eq_(count1,count2,"Feature count differs between OGR driver (%s features) and Shapefile Driver (%s features) when querying the same bbox" % (count1,count2))

View file

@ -6,7 +6,7 @@ from utilities import Todo
class FeatureTest(unittest.TestCase):
def makeOne(self, *args, **kw):
from mapnik2 import Feature
from mapnik import Feature
return Feature(*args, **kw)
def test_default_constructor(self):
@ -14,7 +14,7 @@ class FeatureTest(unittest.TestCase):
self.failUnless(f is not None)
def test_python_extended_constructor(self):
from mapnik2 import Box2d
from mapnik import Box2d
f = self.makeOne(1, 'POLYGON ((35 10, 10 20, 15 40, 45 45, 35 10),(20 30, 35 35, 30 20, 20 30))', foo="bar")
self.failUnlessEqual(f['foo'], 'bar')
self.failUnlessEqual(f.envelope(),Box2d(10.0,10.0,45.0,45.0))
@ -37,7 +37,7 @@ class FeatureTest(unittest.TestCase):
test_val(v)
def test_add_wkt_geometry(self):
from mapnik2 import Box2d
from mapnik import Box2d
def add_geom_wkt(wkt):
f = self.makeOne(1)
self.failUnlessEqual(len(f.geometries()), 0)

View file

@ -4,10 +4,10 @@
from nose.tools import *
from utilities import Todo
import mapnik2
import mapnik
if hasattr(mapnik2,'Expression'):
mapnik2.Filter = mapnik2.Expression
if hasattr(mapnik,'Expression'):
mapnik.Filter = mapnik.Expression
map_ = '''<Map>
<Style name="s">
@ -52,25 +52,25 @@ map_ = '''<Map>
</Map>'''
def test_filter_init():
m = mapnik2.Map(1,1)
mapnik2.load_map_from_string(m,map_)
m = mapnik.Map(1,1)
mapnik.load_map_from_string(m,map_)
filters = []
filters.append(mapnik2.Filter("([region]>=0) and ([region]<=50)"))
filters.append(mapnik2.Filter("(([region]>=0) and ([region]<=50))"))
filters.append(mapnik2.Filter("((([region]>=0) and ([region]<=50)))"))
filters.append(mapnik2.Filter('((([region]>=0) and ([region]<=50)))'))
filters.append(mapnik2.Filter('''((([region]>=0) and ([region]<=50)))'''))
filters.append(mapnik2.Filter('''
filters.append(mapnik.Filter("([region]>=0) and ([region]<=50)"))
filters.append(mapnik.Filter("(([region]>=0) and ([region]<=50))"))
filters.append(mapnik.Filter("((([region]>=0) and ([region]<=50)))"))
filters.append(mapnik.Filter('((([region]>=0) and ([region]<=50)))'))
filters.append(mapnik.Filter('''((([region]>=0) and ([region]<=50)))'''))
filters.append(mapnik.Filter('''
((([region]>=0)
and
([region]<=50)))
'''))
filters.append(mapnik2.Filter('''
filters.append(mapnik.Filter('''
([region]>=0)
and
([region]<=50)
'''))
filters.append(mapnik2.Filter('''
filters.append(mapnik.Filter('''
([region]
>=
0)
@ -91,31 +91,31 @@ def test_filter_init():
s = m.find_style('s2')
eq_(s.filter_mode,mapnik2.filter_mode.FIRST)
eq_(s.filter_mode,mapnik.filter_mode.FIRST)
def test_regex_match():
f = mapnik2.Feature(0)
f = mapnik.Feature(0)
f["name"] = 'test'
expr = mapnik2.Expression("[name].match('test')")
expr = mapnik.Expression("[name].match('test')")
eq_(expr.evaluate(f),True) # 1 == True
def test_unicode_regex_match():
f = mapnik2.Feature(0)
f = mapnik.Feature(0)
f["name"] = 'Québec'
expr = mapnik2.Expression("[name].match('Québec')")
expr = mapnik.Expression("[name].match('Québec')")
eq_(expr.evaluate(f),True) # 1 == True
def test_regex_replace():
f = mapnik2.Feature(0)
f = mapnik.Feature(0)
f["name"] = 'test'
expr = mapnik2.Expression("[name].replace('(\B)|( )','$1 ')")
expr = mapnik.Expression("[name].replace('(\B)|( )','$1 ')")
eq_(expr.evaluate(f),'t e s t')
def test_unicode_regex_replace():
f = mapnik2.Feature(0)
f = mapnik.Feature(0)
f["name"] = 'Québec'
expr = mapnik2.Expression("[name].replace('(\B)|( )','$1 ')")
expr = mapnik.Expression("[name].replace('(\B)|( )','$1 ')")
eq_(expr.evaluate(f), u'Q u é b e c')
if __name__ == "__main__":

View file

@ -2,7 +2,7 @@
from nose.tools import *
import mapnik2, pickle
import mapnik, pickle
# Tests that exercise fonts.
@ -10,7 +10,7 @@ import mapnik2, pickle
# Todo: Add logic to use this TextSymbolizer in a rendering
#@raises(UserWarning)
#def test_invalid_font():
# ts = mapnik2.TextSymbolizer('Name', 'Invalid Font Name', int(8), mapnik2.Color('black'))
# ts = mapnik.TextSymbolizer('Name', 'Invalid Font Name', int(8), mapnik.Color('black'))
if __name__ == "__main__":
[eval(run)() for run in dir() if 'test_' in run]

View file

@ -5,53 +5,53 @@ from nose.tools import *
from utilities import execution_path, save_data, contains_word
import os, mapnik2
import os, mapnik
def test_renders_with_agg():
sym = mapnik2.GlyphSymbolizer("DejaVu Sans Condensed",
mapnik2.Expression("'í'"))
sym = mapnik.GlyphSymbolizer("DejaVu Sans Condensed",
mapnik.Expression("'í'"))
sym.allow_overlap = True
sym.angle = mapnik2.Expression("[azimuth]+90") #+90 so the top of the glyph points upwards
sym.size = mapnik2.Expression("[value]")
sym.color = mapnik2.Expression("'#ff0000'")
sym.angle = mapnik.Expression("[azimuth]+90") #+90 so the top of the glyph points upwards
sym.size = mapnik.Expression("[value]")
sym.color = mapnik.Expression("'#ff0000'")
_map = create_map_and_append_symbolyzer(sym)
im = mapnik2.Image(_map.width,_map.height)
mapnik2.render(_map, im)
im = mapnik.Image(_map.width,_map.height)
mapnik.render(_map, im)
save_data('agg_glyph_symbolizer.png', im.tostring('png'))
assert contains_word('\xff\x00\x00\xff', im.tostring())
def test_renders_with_cairo():
if not mapnik2.has_pycairo():
if not mapnik.has_pycairo():
return
sym = mapnik2.GlyphSymbolizer("DejaVu Sans Condensed",
mapnik2.Expression("'í'"))
sym = mapnik.GlyphSymbolizer("DejaVu Sans Condensed",
mapnik.Expression("'í'"))
sym.allow_overlap = True
sym.angle = mapnik2.Expression("[azimuth]+90") #+90 so the top of the glyph points upwards
sym.size = mapnik2.Expression("[value]")
sym.color = mapnik2.Expression("'#ff0000'")
sym.angle = mapnik.Expression("[azimuth]+90") #+90 so the top of the glyph points upwards
sym.size = mapnik.Expression("[value]")
sym.color = mapnik.Expression("'#ff0000'")
_map = create_map_and_append_symbolyzer(sym)
from cStringIO import StringIO
import cairo
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 256, 256)
mapnik2.render(_map, surface)
im = mapnik2.Image.from_cairo(surface)
mapnik.render(_map, surface)
im = mapnik.Image.from_cairo(surface)
save_data('cairo_glyph_symbolizer.png', im.tostring('png'))
assert contains_word('\xff\x00\x00\xff', im.tostring())
def test_load_save_load_map():
map = mapnik2.Map(256,256)
map = mapnik.Map(256,256)
in_map = "../data/good_maps/glyph_symbolizer.xml"
mapnik2.load_map(map, in_map)
mapnik.load_map(map, in_map)
style = map.find_style('arrows')
sym = style.rules[0].symbols[0]
assert isinstance(sym, mapnik2.GlyphSymbolizer)
assert sym.angle_mode == mapnik2.angle_mode.AZIMUTH
assert isinstance(sym, mapnik.GlyphSymbolizer)
assert sym.angle_mode == mapnik.angle_mode.AZIMUTH
out_map = mapnik2.save_map_to_string(map).decode('utf8')
map = mapnik2.Map(256,256)
mapnik2.load_map_from_string(map, out_map.encode('utf8'))
out_map = mapnik.save_map_to_string(map).decode('utf8')
map = mapnik.Map(256,256)
mapnik.load_map_from_string(map, out_map.encode('utf8'))
assert 'GlyphSymbolizer' in out_map
# make sure non-ascii characters are well supported since most interesting
# glyphs for symbology are usually in that range
@ -68,21 +68,21 @@ def setup():
def create_map_and_append_symbolyzer(sym):
srs = '+init=epsg:32630'
lyr = mapnik2.Layer('arrows')
lyr.datasource = mapnik2.Shapefile(
lyr = mapnik.Layer('arrows')
lyr.datasource = mapnik.Shapefile(
file = '../data/shp/arrows.shp',
)
lyr.srs = srs
_map = mapnik2.Map(256,256, srs)
style = mapnik2.Style()
rule = mapnik2.Rule()
_map = mapnik.Map(256,256, srs)
style = mapnik.Style()
rule = mapnik.Rule()
rule.symbols.append(sym)
# put a test symbolizer to see what is the azimuth being read
ts = mapnik2.TextSymbolizer(mapnik2.Expression('[azimuth]'),
ts = mapnik.TextSymbolizer(mapnik.Expression('[azimuth]'),
"DejaVu Sans Book",
10,
mapnik2.Color("black"))
mapnik.Color("black"))
ts.allow_overlap = True
rule.symbols.append(ts)
@ -90,7 +90,7 @@ def create_map_and_append_symbolyzer(sym):
_map.append_style('foo', style)
lyr.styles.append('foo')
_map.layers.append(lyr)
_map.zoom_to_box(mapnik2.Box2d(0,0,8,8))
_map.zoom_to_box(mapnik.Box2d(0,0,8,8))
return _map
if __name__ == "__main__":

View file

@ -5,7 +5,7 @@ from nose.tools import *
from utilities import execution_path
from utilities import Todo
import mapnik2
import mapnik
def setup():
# All of the paths used are relative, if we run the tests
@ -14,7 +14,7 @@ def setup():
def test_introspect_symbolizers():
# create a symbolizer
p = mapnik2.PointSymbolizer(mapnik2.PathExpression("../data/images/dummy.png"))
p = mapnik.PointSymbolizer(mapnik.PathExpression("../data/images/dummy.png"))
p.allow_overlap = True
p.opacity = 0.5
@ -29,11 +29,11 @@ def test_introspect_symbolizers():
eq_(p.filename,'../data/images/dummy.png')
# contruct objects to hold it
r = mapnik2.Rule()
r = mapnik.Rule()
r.symbols.append(p)
s = mapnik2.Style()
s = mapnik.Style()
s.rules.append(r)
m = mapnik2.Map(0,0)
m = mapnik.Map(0,0)
m.append_style('s',s)
# try to figure out what is
@ -51,7 +51,7 @@ def test_introspect_symbolizers():
sym = syms[0]
# this is hackish at best
p2 = sym.symbol()
assert isinstance(p2,mapnik2.PointSymbolizer)
assert isinstance(p2,mapnik.PointSymbolizer)
eq_(p2.allow_overlap, True)
eq_(p2.opacity, 0.5)
@ -60,7 +60,7 @@ def test_introspect_symbolizers():
## but we need to be able to do:
p2 = syms[0] # get the actual symbolizer, not the variant object
# this will throw for now...
assert isinstance(p2,mapnik2.PointSymbolizer)
assert isinstance(p2,mapnik.PointSymbolizer)
eq_(p2.allow_overlap, True)
eq_(p2.opacity, 0.5)

View file

@ -5,7 +5,7 @@ from nose.tools import *
import os
from nose.tools import *
from utilities import execution_path
import mapnik2
import mapnik
def setup():
# All of the paths used are relative, if we run the tests
@ -30,9 +30,9 @@ def test_adding_datasource_to_layer():
</Map>
'''
m = mapnik2.Map(256, 256)
m = mapnik.Map(256, 256)
mapnik2.load_map_from_string(m, map_string)
mapnik.load_map_from_string(m, map_string)
# validate it loaded fine
eq_(m.layers[0].styles[0],'world_borders_style')
@ -53,7 +53,7 @@ def test_adding_datasource_to_layer():
eq_(lyr.srs,'+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')
# now add a datasource one...
ds = mapnik2.Shapefile(file='../data/shp/world_merc.shp')
ds = mapnik.Shapefile(file='../data/shp/world_merc.shp')
m.layers[0].datasource = ds
# now ensure it is attached

View file

@ -3,7 +3,7 @@
from nose.tools import *
from utilities import execution_path
import os, sys, glob, mapnik2
import os, sys, glob, mapnik
def setup():
# All of the paths used are relative, if we run the tests
@ -13,15 +13,15 @@ def setup():
# We expect these files to not raise any
# exceptions at all
def assert_loads_successfully(file):
m = mapnik2.Map(512, 512)
m = mapnik.Map(512, 512)
strict = True
mapnik2.load_map(m, file, strict)
mapnik.load_map(m, file, strict)
# libxml2 is not smart about paths, and clips the last directory off
# of a path if it does not end in a trailing slash
base_path = os.path.dirname(file) + '/'
mapnik2.load_map_from_string(m,open(file,'rb').read(),strict,base_path)
mapnik.load_map_from_string(m,open(file,'rb').read(),strict,base_path)
# We expect these files to raise a RuntimeError
@ -29,10 +29,10 @@ def assert_loads_successfully(file):
# of exception)
@raises(RuntimeError)
def assert_raises_runtime_error(file):
m = mapnik2.Map(512, 512)
m = mapnik.Map(512, 512)
strict = True
mapnik2.load_map(m, file, strict)
mapnik.load_map(m, file, strict)
def test_broken_files():
broken_files = glob.glob("../data/broken_maps/*.xml")

View file

@ -4,7 +4,7 @@ from nose.tools import *
from subprocess import call
import os
#import os, sys, glob, mapnik2
#import os, sys, glob, mapnik
#def test():
# # mapnik-config program

View file

@ -8,11 +8,11 @@ class MemoryDatasource(unittest.TestCase):
ids = itertools.count(0)
def makeOne(self, *args, **kw):
from mapnik2 import MemoryDatasource
from mapnik import MemoryDatasource
return MemoryDatasource(*args, **kw)
def makeFeature(self, wkt, **properties):
from mapnik2 import Feature
from mapnik import Feature
f = Feature(self.ids.next())
f.add_geometries_from_wkt(wkt)
for k,v in properties.iteritems():
@ -29,7 +29,7 @@ class MemoryDatasource(unittest.TestCase):
md.add_feature(self.makeFeature('Point(2 3)', foo='bar'))
self.failUnlessEqual(md.num_features(), 1)
from mapnik2 import Coord
from mapnik import Coord
retrieved = md.features_at_point(Coord(2,3)).features
self.failUnlessEqual(len(retrieved), 1)
f = retrieved[0]

View file

@ -6,7 +6,7 @@ from nose.tools import *
from utilities import execution_path
from utilities import Todo
import mapnik2, pickle
import mapnik, pickle
def setup():
# All of the paths used are relative, if we run the tests
@ -17,44 +17,44 @@ def setup():
# LineSymbolizer initialization
def test_line_symbolizer_init():
s = mapnik2.LineSymbolizer()
eq_(s.rasterizer, mapnik2.line_rasterizer.FULL)
s = mapnik.LineSymbolizer()
eq_(s.rasterizer, mapnik.line_rasterizer.FULL)
# ShieldSymbolizer initialization
def test_shieldsymbolizer_init():
s = mapnik2.ShieldSymbolizer(mapnik2.Expression('[Field Name]'), 'DejaVu Sans Bold', 6, mapnik2.Color('#000000'), mapnik2.PathExpression('../data/images/dummy.png'))
s = mapnik.ShieldSymbolizer(mapnik.Expression('[Field Name]'), 'DejaVu Sans Bold', 6, mapnik.Color('#000000'), mapnik.PathExpression('../data/images/dummy.png'))
eq_(s.anchor, (0.0,0.5,))
eq_(s.displacement, (0.0,0.0))
eq_(s.allow_overlap, False)
eq_(s.avoid_edges, False)
eq_(s.character_spacing,0)
eq_(str(s.name), str(mapnik2.Expression('[Field Name]')))
eq_(str(s.name), str(mapnik.Expression('[Field Name]')))
eq_(s.face_name, 'DejaVu Sans Bold')
eq_(s.allow_overlap, False)
eq_(s.fill, mapnik2.Color('#000000'))
eq_(s.fill, mapnik.Color('#000000'))
eq_(s.force_odd_labels, False)
eq_(s.halo_fill, mapnik2.Color('rgb(255,255,255)'))
eq_(s.halo_fill, mapnik.Color('rgb(255,255,255)'))
eq_(s.halo_radius, 0)
eq_(s.label_placement, mapnik2.label_placement.POINT_PLACEMENT)
eq_(s.label_placement, mapnik.label_placement.POINT_PLACEMENT)
eq_(s.minimum_distance, 0.0)
eq_(s.text_ratio, 0)
eq_(s.text_size, 6)
eq_(s.wrap_width, 0)
eq_(s.vertical_alignment, mapnik2.vertical_alignment.MIDDLE)
eq_(s.vertical_alignment, mapnik.vertical_alignment.MIDDLE)
eq_(s.label_spacing, 0)
eq_(s.label_position_tolerance, 0)
# 22.5 * M_PI/180.0 initialized by default
assert_almost_equal(s.max_char_angle_delta, 0.39269908169872414)
eq_(s.wrap_character, ' ')
eq_(s.text_transform, mapnik2.text_transform.NONE)
eq_(s.text_transform, mapnik.text_transform.NONE)
eq_(s.line_spacing, 0)
eq_(s.character_spacing, 0)
# r1341
eq_(s.wrap_before, False)
eq_(s.horizontal_alignment, mapnik2.horizontal_alignment.MIDDLE)
eq_(s.justify_alignment, mapnik2.justify_alignment.MIDDLE)
eq_(s.horizontal_alignment, mapnik.horizontal_alignment.MIDDLE)
eq_(s.justify_alignment, mapnik.justify_alignment.MIDDLE)
eq_(s.opacity, 1.0)
# r2300
@ -70,7 +70,7 @@ def test_shieldsymbolizer_init():
eq_(s.transform, 'matrix(1, 0, 0, 1, 0, 0)')
raise Todo("FontSet pickling support needed: http://trac.mapnik2.org/ticket/348")
raise Todo("FontSet pickling support needed: http://trac.mapnik.org/ticket/348")
eq_(s.fontset, '')
@ -79,53 +79,53 @@ def test_shieldsymbolizer_init():
# so it does not make sense to throw...
#@raises(RuntimeError)
#def test_shieldsymbolizer_missing_image():
# s = mapnik2.ShieldSymbolizer(mapnik2.Expression('[Field Name]'), 'DejaVu Sans Bold', 6, mapnik2.Color('#000000'), mapnik2.PathExpression('../#data/images/broken.png'))
# s = mapnik.ShieldSymbolizer(mapnik.Expression('[Field Name]'), 'DejaVu Sans Bold', 6, mapnik.Color('#000000'), mapnik.PathExpression('../#data/images/broken.png'))
def test_polygonsymbolizer_init():
p = mapnik2.PolygonSymbolizer()
p = mapnik.PolygonSymbolizer()
eq_(p.fill, mapnik2.Color('gray'))
eq_(p.fill, mapnik.Color('gray'))
eq_(p.fill_opacity, 1)
eq_(p.placement, mapnik2.point_placement.CENTROID)
eq_(p.placement, mapnik.point_placement.CENTROID)
p = mapnik2.PolygonSymbolizer(mapnik2.Color('blue'))
p.placement = mapnik2.point_placement.INTERIOR
p = mapnik.PolygonSymbolizer(mapnik.Color('blue'))
p.placement = mapnik.point_placement.INTERIOR
eq_(p.fill, mapnik2.Color('blue'))
eq_(p.fill, mapnik.Color('blue'))
eq_(p.fill_opacity, 1)
eq_(p.placement, mapnik2.point_placement.INTERIOR)
eq_(p.placement, mapnik.point_placement.INTERIOR)
# PointSymbolizer initialization
def test_pointsymbolizer_init():
p = mapnik2.PointSymbolizer()
p = mapnik.PointSymbolizer()
eq_(p.allow_overlap, False)
eq_(p.opacity,1)
eq_(p.filename,'')
eq_(p.ignore_placement,False)
eq_(p.placement, mapnik2.point_placement.CENTROID)
eq_(p.placement, mapnik.point_placement.CENTROID)
p = mapnik2.PointSymbolizer(mapnik2.PathExpression("../data/images/dummy.png"))
p = mapnik.PointSymbolizer(mapnik.PathExpression("../data/images/dummy.png"))
p.allow_overlap = True
p.opacity = 0.5
p.ignore_placement = True
p.placement = mapnik2.point_placement.INTERIOR
p.placement = mapnik.point_placement.INTERIOR
eq_(p.allow_overlap, True)
eq_(p.opacity, 0.5)
eq_(p.filename,'../data/images/dummy.png')
eq_(p.ignore_placement,True)
eq_(p.placement, mapnik2.point_placement.INTERIOR)
eq_(p.placement, mapnik.point_placement.INTERIOR)
# PointSymbolizer missing image file
# images paths are now PathExpressions are evaluated at runtime
# so it does not make sense to throw...
#@raises(RuntimeError)
#def test_pointsymbolizer_missing_image():
# p = mapnik2.PointSymbolizer(mapnik2.PathExpression("../data/images/broken.png"))
# p = mapnik.PointSymbolizer(mapnik.PathExpression("../data/images/broken.png"))
# PointSymbolizer pickling
def test_pointsymbolizer_pickle():
raise Todo("point_symbolizer pickling currently disabled")
p = mapnik2.PointSymbolizer(mapnik2.PathExpression("../data/images/dummy.png"))
p = mapnik.PointSymbolizer(mapnik.PathExpression("../data/images/dummy.png"))
p2 = pickle.loads(pickle.dumps(p,pickle.HIGHEST_PROTOCOL))
# image type, width, and height only used in contructor...
eq_(p.filename, p2.filename)
@ -136,19 +136,19 @@ def test_pointsymbolizer_pickle():
# PolygonSymbolizer initialization
def test_polygonsymbolizer_init():
p = mapnik2.PolygonSymbolizer()
p = mapnik.PolygonSymbolizer()
eq_(p.fill, mapnik2.Color('gray'))
eq_(p.fill, mapnik.Color('gray'))
eq_(p.fill_opacity, 1)
p = mapnik2.PolygonSymbolizer(mapnik2.Color('blue'))
p = mapnik.PolygonSymbolizer(mapnik.Color('blue'))
eq_(p.fill, mapnik2.Color('blue'))
eq_(p.fill, mapnik.Color('blue'))
eq_(p.fill_opacity, 1)
# PolygonSymbolizer pickling
def test_polygonsymbolizer_pickle():
p = mapnik2.PolygonSymbolizer(mapnik2.Color('black'))
p = mapnik.PolygonSymbolizer(mapnik.Color('black'))
p.fill_opacity = .5
# does not work for some reason...
#eq_(pickle.loads(pickle.dumps(p)), p)
@ -159,28 +159,28 @@ def test_polygonsymbolizer_pickle():
# Stroke initialization
def test_stroke_init():
s = mapnik2.Stroke()
s = mapnik.Stroke()
eq_(s.width, 1)
eq_(s.opacity, 1)
eq_(s.color, mapnik2.Color('black'))
eq_(s.line_cap, mapnik2.line_cap.BUTT_CAP)
eq_(s.line_join, mapnik2.line_join.MITER_JOIN)
eq_(s.color, mapnik.Color('black'))
eq_(s.line_cap, mapnik.line_cap.BUTT_CAP)
eq_(s.line_join, mapnik.line_join.MITER_JOIN)
eq_(s.gamma,1.0)
s = mapnik2.Stroke(mapnik2.Color('blue'), 5.0)
s = mapnik.Stroke(mapnik.Color('blue'), 5.0)
s.gamma = .5
eq_(s.width, 5)
eq_(s.opacity, 1)
eq_(s.color, mapnik2.Color('blue'))
eq_(s.color, mapnik.Color('blue'))
eq_(s.gamma, .5)
eq_(s.line_cap, mapnik2.line_cap.BUTT_CAP)
eq_(s.line_join, mapnik2.line_join.MITER_JOIN)
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 = mapnik2.Stroke()
s = mapnik.Stroke()
s.add_dash(1,2)
s.add_dash(3,4)
s.add_dash(5,6)
@ -189,10 +189,10 @@ def test_stroke_dash_arrays():
# Stroke pickling
def test_stroke_pickle():
s = mapnik2.Stroke(mapnik2.Color('black'),4.5)
s = mapnik.Stroke(mapnik.Color('black'),4.5)
eq_(s.width, 4.5)
eq_(s.color, mapnik2.Color('black'))
eq_(s.color, mapnik.Color('black'))
s.add_dash(1,2)
s.add_dash(3,4)
@ -209,34 +209,34 @@ def test_stroke_pickle():
# LineSymbolizer initialization
def test_linesymbolizer_init():
l = mapnik2.LineSymbolizer()
l = mapnik.LineSymbolizer()
eq_(l.stroke.width, 1)
eq_(l.stroke.opacity, 1)
eq_(l.stroke.color, mapnik2.Color('black'))
eq_(l.stroke.line_cap, mapnik2.line_cap.BUTT_CAP)
eq_(l.stroke.line_join, mapnik2.line_join.MITER_JOIN)
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 = mapnik2.LineSymbolizer(mapnik2.Color('blue'), 5.0)
l = mapnik.LineSymbolizer(mapnik.Color('blue'), 5.0)
eq_(l.stroke.width, 5)
eq_(l.stroke.opacity, 1)
eq_(l.stroke.color, mapnik2.Color('blue'))
eq_(l.stroke.line_cap, mapnik2.line_cap.BUTT_CAP)
eq_(l.stroke.line_join, mapnik2.line_join.MITER_JOIN)
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 = mapnik2.Stroke(mapnik2.Color('blue'), 5.0)
l = mapnik2.LineSymbolizer(s)
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, mapnik2.Color('blue'))
eq_(l.stroke.line_cap, mapnik2.line_cap.BUTT_CAP)
eq_(l.stroke.line_join, mapnik2.line_join.MITER_JOIN)
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)
# LineSymbolizer pickling
def test_linesymbolizer_pickle():
p = mapnik2.LineSymbolizer()
p = mapnik.LineSymbolizer()
p2 = pickle.loads(pickle.dumps(p,pickle.HIGHEST_PROTOCOL))
# line and stroke eq fails, so we compare attributes for now..
s,s2 = p.stroke, p2.stroke
@ -249,7 +249,7 @@ def test_linesymbolizer_pickle():
# Shapefile initialization
def test_shapefile_init():
s = mapnik2.Shapefile(file='../../demo/data/boundaries')
s = mapnik.Shapefile(file='../../demo/data/boundaries')
e = s.envelope()
@ -260,7 +260,7 @@ def test_shapefile_init():
# Shapefile properties
def test_shapefile_properties():
s = mapnik2.Shapefile(file='../../demo/data/boundaries', encoding='latin1')
s = mapnik.Shapefile(file='../../demo/data/boundaries', encoding='latin1')
f = s.features_at_point(s.envelope().center()).features[0]
eq_(f['CGNS_FID'], u'6f733341ba2011d892e2080020a0f4c9')
@ -279,22 +279,22 @@ def test_shapefile_properties():
# TextSymbolizer initialization
def test_textsymbolizer_init():
ts = mapnik2.TextSymbolizer(mapnik2.Expression('[Field_Name]'), 'Font Name', 8, mapnik2.Color('black'))
ts = mapnik.TextSymbolizer(mapnik.Expression('[Field_Name]'), 'Font Name', 8, mapnik.Color('black'))
eq_(str(ts.name), str(mapnik2.Expression('[Field_Name]')))
eq_(str(ts.name), str(mapnik.Expression('[Field_Name]')))
eq_(ts.face_name, 'Font Name')
eq_(ts.text_size, 8)
eq_(ts.fill, mapnik2.Color('black'))
eq_(ts.label_placement, mapnik2.label_placement.POINT_PLACEMENT)
eq_(ts.fill, mapnik.Color('black'))
eq_(ts.label_placement, mapnik.label_placement.POINT_PLACEMENT)
# TextSymbolizer pickling
def test_textsymbolizer_pickle():
ts = mapnik2.TextSymbolizer(mapnik2.Expression('[Field_Name]'), 'Font Name', 8, mapnik2.Color('black'))
ts = mapnik.TextSymbolizer(mapnik.Expression('[Field_Name]'), 'Font Name', 8, mapnik.Color('black'))
eq_(str(ts.name), str(mapnik2.Expression('[Field_Name]')))
eq_(str(ts.name), str(mapnik.Expression('[Field_Name]')))
eq_(ts.face_name, 'Font Name')
eq_(ts.text_size, 8)
eq_(ts.fill, mapnik2.Color('black'))
eq_(ts.fill, mapnik.Color('black'))
raise Todo("text_symbolizer pickling currently disabled")
@ -333,15 +333,15 @@ def test_textsymbolizer_pickle():
# r2300
eq_(s.minimum_padding, 0.0)
raise Todo("FontSet pickling support needed: http://trac.mapnik2.org/ticket/348")
raise Todo("FontSet pickling support needed: http://trac.mapnik.org/ticket/348")
eq_(ts.fontset, ts2.fontset)
# Map initialization
def test_layer_init():
l = mapnik2.Layer('test')
l = mapnik.Layer('test')
eq_(l.name,'test')
eq_(l.envelope(),mapnik2.Box2d())
eq_(l.envelope(),mapnik.Box2d())
eq_(l.clear_label_cache,False)
eq_(l.cache_features,False)
eq_(l.visible(1),True)
@ -354,14 +354,14 @@ def test_layer_init():
# Map initialization
def test_map_init():
m = mapnik2.Map(256, 256)
m = mapnik.Map(256, 256)
eq_(m.width, 256)
eq_(m.height, 256)
eq_(m.srs, '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')
eq_(m.base, '')
m = mapnik2.Map(256, 256, '+proj=latlong')
m = mapnik.Map(256, 256, '+proj=latlong')
eq_(m.srs, '+proj=latlong')
# Map initialization from string
@ -387,19 +387,19 @@ def test_map_init_from_string():
</Layer>
</Map>'''
m = mapnik2.Map(600, 300)
m = mapnik.Map(600, 300)
eq_(m.base, '')
mapnik2.load_map_from_string(m, map_string)
mapnik.load_map_from_string(m, map_string)
eq_(m.base, './')
mapnik2.load_map_from_string(m, map_string, False, "") # this "" will have no effect
mapnik.load_map_from_string(m, map_string, False, "") # this "" will have no effect
eq_(m.base, './')
try:
mapnik2.load_map_from_string(m, map_string, False, "/tmp")
mapnik.load_map_from_string(m, map_string, False, "/tmp")
except RuntimeError:
pass # runtime error expected because shapefile path should be wrong and datasource will throw
eq_(m.base, '/tmp') # /tmp will be set despite the exception because load_map mostly worked
m.base = 'foo'
mapnik2.load_map_from_string(m, map_string, True, ".")
mapnik.load_map_from_string(m, map_string, True, ".")
eq_(m.base, '.')
raise(Todo("Need to write more map property tests in 'object_test.py'..."))
@ -408,11 +408,11 @@ def test_map_pickle():
# Fails due to scale() not matching, possibly other things
raise(Todo("Map does not support pickling yet (Tickets #345)."))
m = mapnik2.Map(256, 256)
m = mapnik.Map(256, 256)
eq_(pickle.loads(pickle.dumps(m)), m)
m = mapnik2.Map(256, 256, '+proj=latlong')
m = mapnik.Map(256, 256, '+proj=latlong')
eq_(pickle.loads(pickle.dumps(m)), m)
@ -420,14 +420,14 @@ def test_map_pickle():
@raises(Exception) # Boost.Python.ArgumentError
def test_color_init_errors():
c = mapnik2.Color()
c = mapnik.Color()
@raises(RuntimeError)
def test_color_init_errors():
c = mapnik2.Color('foo') # mapnik config
c = mapnik.Color('foo') # mapnik config
def test_color_init():
c = mapnik2.Color('blue')
c = mapnik.Color('blue')
eq_(c.a, 255)
eq_(c.r, 0)
@ -436,7 +436,7 @@ def test_color_init():
eq_(c.to_hex_string(), '#0000ff')
c = mapnik2.Color('#f2eff9')
c = mapnik.Color('#f2eff9')
eq_(c.a, 255)
eq_(c.r, 242)
@ -445,7 +445,7 @@ def test_color_init():
eq_(c.to_hex_string(), '#f2eff9')
c = mapnik2.Color('rgb(50%,50%,50%)')
c = mapnik.Color('rgb(50%,50%,50%)')
eq_(c.a, 255)
eq_(c.r, 128)
@ -454,7 +454,7 @@ def test_color_init():
eq_(c.to_hex_string(), '#808080')
c = mapnik2.Color(0, 64, 128)
c = mapnik.Color(0, 64, 128)
eq_(c.a, 255)
eq_(c.r, 0)
@ -463,7 +463,7 @@ def test_color_init():
eq_(c.to_hex_string(), '#004080')
c = mapnik2.Color(0, 64, 128, 192)
c = mapnik.Color(0, 64, 128, 192)
eq_(c.a, 192)
eq_(c.r, 0)
@ -475,9 +475,9 @@ def test_color_init():
# Color equality
def test_color_equality():
c1 = mapnik2.Color('blue')
c2 = mapnik2.Color(0,0,255)
c3 = mapnik2.Color('black')
c1 = mapnik.Color('blue')
c2 = mapnik.Color(0,0,255)
c3 = mapnik.Color('black')
c3.r = 0
@ -488,9 +488,9 @@ def test_color_equality():
eq_(c1, c2)
eq_(c1, c3)
c1 = mapnik2.Color(0, 64, 128)
c2 = mapnik2.Color(0, 64, 128)
c3 = mapnik2.Color(0, 0, 0)
c1 = mapnik.Color(0, 64, 128)
c2 = mapnik.Color(0, 64, 128)
c3 = mapnik.Color(0, 0, 0)
c3.r = 0
c3.g = 64
@ -499,9 +499,9 @@ def test_color_equality():
eq_(c1, c2)
eq_(c1, c3)
c1 = mapnik2.Color(0, 64, 128, 192)
c2 = mapnik2.Color(0, 64, 128, 192)
c3 = mapnik2.Color(0, 0, 0, 255)
c1 = mapnik.Color(0, 64, 128, 192)
c2 = mapnik.Color(0, 64, 128, 192)
c3 = mapnik.Color(0, 0, 0, 255)
c3.r = 0
c3.g = 64
@ -511,35 +511,35 @@ def test_color_equality():
eq_(c1, c2)
eq_(c1, c3)
c1 = mapnik2.Color('rgb(50%,50%,50%)')
c2 = mapnik2.Color(128, 128, 128, 255)
c3 = mapnik2.Color('#808080')
c4 = mapnik2.Color('gray')
c1 = mapnik.Color('rgb(50%,50%,50%)')
c2 = mapnik.Color(128, 128, 128, 255)
c3 = mapnik.Color('#808080')
c4 = mapnik.Color('gray')
eq_(c1, c2)
eq_(c1, c3)
eq_(c1, c4)
c1 = mapnik2.Color('hsl(0, 100%, 50%)') # red
c2 = mapnik2.Color('hsl(120, 100%, 50%)') # lime
c3 = mapnik2.Color('hsla(240, 100%, 50%, 0.5)') # semi-transparent solid blue
c1 = mapnik.Color('hsl(0, 100%, 50%)') # red
c2 = mapnik.Color('hsl(120, 100%, 50%)') # lime
c3 = mapnik.Color('hsla(240, 100%, 50%, 0.5)') # semi-transparent solid blue
eq_(c1, mapnik2.Color('red'))
eq_(c2, mapnik2.Color('lime'))
eq_(c3, mapnik2.Color(0,0,255,128))
eq_(c1, mapnik.Color('red'))
eq_(c2, mapnik.Color('lime'))
eq_(c3, mapnik.Color(0,0,255,128))
# Color pickling
def test_color_pickle():
c = mapnik2.Color('blue')
c = mapnik.Color('blue')
eq_(pickle.loads(pickle.dumps(c)), c)
c = mapnik2.Color(0, 64, 128)
c = mapnik.Color(0, 64, 128)
eq_(pickle.loads(pickle.dumps(c)), c)
c = mapnik2.Color(0, 64, 128, 192)
c = mapnik.Color(0, 64, 128, 192)
eq_(pickle.loads(pickle.dumps(c)), c)
@ -548,7 +548,7 @@ def test_rule_init():
min_scale = 5
max_scale = 10
r = mapnik2.Rule()
r = mapnik.Rule()
eq_(r.name, '')
eq_(r.title, '')
@ -557,19 +557,19 @@ def test_rule_init():
eq_(r.has_else(), False)
eq_(r.has_also(), False)
r = mapnik2.Rule()
r = mapnik.Rule()
r.set_else(True)
eq_(r.has_else(), True)
eq_(r.has_also(), False)
r = mapnik2.Rule()
r = mapnik.Rule()
r.set_also(True)
eq_(r.has_else(), False)
eq_(r.has_also(), True)
r = mapnik2.Rule("Name")
r = mapnik.Rule("Name")
eq_(r.name, 'Name')
eq_(r.title, '')
@ -578,7 +578,7 @@ def test_rule_init():
eq_(r.has_else(), False)
eq_(r.has_also(), False)
r = mapnik2.Rule("Name", "Title")
r = mapnik.Rule("Name", "Title")
eq_(r.name, 'Name')
eq_(r.title, 'Title')
@ -587,7 +587,7 @@ def test_rule_init():
eq_(r.has_else(), False)
eq_(r.has_also(), False)
r = mapnik2.Rule("Name", "Title", min_scale)
r = mapnik.Rule("Name", "Title", min_scale)
eq_(r.name, 'Name')
eq_(r.title, 'Title')
@ -596,7 +596,7 @@ def test_rule_init():
eq_(r.has_else(), False)
eq_(r.has_also(), False)
r = mapnik2.Rule("Name", "Title", min_scale, max_scale)
r = mapnik.Rule("Name", "Title", min_scale, max_scale)
eq_(r.name, 'Name')
eq_(r.title, 'Title')
@ -607,14 +607,14 @@ def test_rule_init():
# Coordinate initialization
def test_coord_init():
c = mapnik2.Coord(100, 100)
c = mapnik.Coord(100, 100)
eq_(c.x, 100)
eq_(c.y, 100)
# Coordinate multiplication
def test_coord_multiplication():
c = mapnik2.Coord(100, 100)
c = mapnik.Coord(100, 100)
c *= 2
eq_(c.x, 200)
@ -622,7 +622,7 @@ def test_coord_multiplication():
# Box2d initialization
def test_envelope_init():
e = mapnik2.Box2d(100, 100, 200, 200)
e = mapnik.Box2d(100, 100, 200, 200)
assert_true(e.contains(100, 100))
assert_true(e.contains(100, 200))
@ -661,9 +661,9 @@ def test_envelope_init():
# Box2d static initialization
def test_envelope_static_init():
e = mapnik2.Box2d.from_string('100 100 200 200')
e2 = mapnik2.Box2d.from_string('100,100,200,200')
e3 = mapnik2.Box2d.from_string('100 , 100 , 200 , 200')
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)
@ -704,13 +704,13 @@ def test_envelope_static_init():
# Box2d pickling
def test_envelope_pickle():
e = mapnik2.Box2d(100, 100, 200, 200)
e = mapnik.Box2d(100, 100, 200, 200)
eq_(pickle.loads(pickle.dumps(e)), e)
# Box2d multiplication
def test_envelope_multiplication():
e = mapnik2.Box2d(100, 100, 200, 200)
e = mapnik.Box2d(100, 100, 200, 200)
e *= 2
assert_true(e.contains(50, 50))
@ -741,20 +741,20 @@ def test_envelope_multiplication():
# Box2d clipping
def test_envelope_pickle():
e1 = mapnik2.Box2d(-180,-90,180,90)
e2 = mapnik2.Box2d(-120,40,-110,48)
e1 = mapnik.Box2d(-180,-90,180,90)
e2 = mapnik.Box2d(-120,40,-110,48)
e1.clip(e2)
eq_(e1,e2)
# madagascar in merc
e1 = mapnik2.Box2d(4772116.5490, -2744395.0631, 5765186.4203, -1609458.0673)
e2 = mapnik2.Box2d(5124338.3753, -2240522.1727, 5207501.8621, -2130452.8520)
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 = mapnik2.Box2d(163.8062, -47.1897, 179.3628, -33.9069)
e2 = mapnik2.Box2d(173.7378, -39.6395, 174.4849, -38.9252)
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)

View file

@ -0,0 +1,271 @@
#!/usr/bin/env python
from nose.tools import *
import atexit
import time
from utilities import execution_path
from subprocess import Popen, PIPE
import os, mapnik
MAPNIK_TEST_DBNAME = 'mapnik-tmp-postgis-test-db'
POSTGIS_TEMPLATE_DBNAME = 'template_postgis'
SHAPEFILE = os.path.join(execution_path('.'),'../data/shp/world_merc.shp')
SQL_DUMPS = os.path.join(execution_path('.'),'../data/sql')
def setup():
# All of the paths used are relative, if we run the tests
# from another directory we need to chdir()
os.chdir(execution_path('.'))
def call(cmd,silent=False):
stdin, stderr = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE).communicate()
if not stderr:
return stdin.strip()
elif not silent and not 'NOTICE' in stderr:
raise RuntimeError(stderr.strip())
def psql_can_connect():
"""Test ability to connect to a postgis template db with no options.
Basically, to run these tests your user must have full read
access over unix sockets without supplying a password. This
keeps these tests simple and focused on postgis not on postgres
auth issues.
"""
try:
call('psql %s -c "select postgis_version()"' % POSTGIS_TEMPLATE_DBNAME)
return True
except RuntimeError, e:
print 'Notice: skipping postgis tests (connection)'
return False
def shp2pgsql_on_path():
"""Test for presence of shp2pgsql on the user path.
We require this program to load test data into a temporarily database.
"""
try:
call('shp2pgsql')
return True
except RuntimeError, e:
print 'Notice: skipping postgis tests (shp2pgsql)'
return False
def createdb_and_dropdb_on_path():
"""Test for presence of dropdb/createdb on user path.
We require these programs to setup and teardown the testing db.
"""
try:
call('createdb --help')
call('dropdb --help')
return True
except RuntimeError, e:
print 'Notice: skipping postgis tests (createdb/dropdb)'
return False
insert_table_1 = """
CREATE TABLE test(gid serial PRIMARY KEY, geom geometry);
INSERT INTO test(geom) values (GeomFromEWKT('SRID=4326;POINT(0 0)'));
INSERT INTO test(geom) values (GeomFromEWKT('SRID=4326;POINT(-2 2)'));
INSERT INTO test(geom) values (GeomFromEWKT('SRID=4326;MULTIPOINT(2 1,1 2)'));
INSERT INTO test(geom) values (GeomFromEWKT('SRID=4326;LINESTRING(0 0,1 1,1 2)'));
INSERT INTO test(geom) values (GeomFromEWKT('SRID=4326;MULTILINESTRING((1 0,0 1,3 2),(3 2,5 4))'));
INSERT INTO test(geom) values (GeomFromEWKT('SRID=4326;POLYGON((0 0,4 0,4 4,0 4,0 0),(1 1, 2 1, 2 2, 1 2,1 1))'));
INSERT INTO test(geom) values (GeomFromEWKT('SRID=4326;MULTIPOLYGON(((1 1,3 1,3 3,1 3,1 1),(1 1,2 1,2 2,1 2,1 1)), ((-1 -1,-1 -2,-2 -2,-2 -1,-1 -1)))'));
INSERT INTO test(geom) values (GeomFromEWKT('SRID=4326;GEOMETRYCOLLECTION(POLYGON((1 1, 2 1, 2 2, 1 2,1 1)),POINT(2 3),LINESTRING(2 3,3 4))'));
"""
insert_table_2 = """
CREATE TABLE test2(manual_id int4 PRIMARY KEY, geom geometry);
INSERT INTO test2(manual_id, geom) values (0, GeomFromEWKT('SRID=4326;POINT(0 0)'));
INSERT INTO test2(manual_id, geom) values (1, GeomFromEWKT('SRID=4326;POINT(0 0)'));
INSERT INTO test2(manual_id, geom) values (1000, GeomFromEWKT('SRID=4326;POINT(0 0)'));
INSERT INTO test2(manual_id, geom) values (-1000, GeomFromEWKT('SRID=4326;POINT(0 0)'));
INSERT INTO test2(manual_id, geom) values (2147483647, GeomFromEWKT('SRID=4326;POINT(0 0)'));
INSERT INTO test2(manual_id, geom) values (-2147483648, GeomFromEWKT('SRID=4326;POINT(0 0)'));
"""
insert_table_3 = """
CREATE TABLE test3(non_id bigint, manual_id int4, geom geometry);
INSERT INTO test3(non_id, manual_id, geom) values (9223372036854775807, 0, GeomFromEWKT('SRID=4326;POINT(0 0)'));
INSERT INTO test3(non_id, manual_id, geom) values (9223372036854775807, 1, GeomFromEWKT('SRID=4326;POINT(0 0)'));
INSERT INTO test3(non_id, manual_id, geom) values (9223372036854775807, 1000, GeomFromEWKT('SRID=4326;POINT(0 0)'));
INSERT INTO test3(non_id, manual_id, geom) values (9223372036854775807, -1000, GeomFromEWKT('SRID=4326;POINT(0 0)'));
INSERT INTO test3(non_id, manual_id, geom) values (9223372036854775807, 2147483647, GeomFromEWKT('SRID=4326;POINT(0 0)'));
INSERT INTO test3(non_id, manual_id, geom) values (9223372036854775807, -2147483648, GeomFromEWKT('SRID=4326;POINT(0 0)'));
"""
insert_table_4 = """
CREATE TABLE test4(non_id int4, manual_id int8 PRIMARY KEY, geom geometry);
INSERT INTO test4(non_id, manual_id, geom) values (0, 0, GeomFromEWKT('SRID=4326;POINT(0 0)'));
INSERT INTO test4(non_id, manual_id, geom) values (0, 1, GeomFromEWKT('SRID=4326;POINT(0 0)'));
INSERT INTO test4(non_id, manual_id, geom) values (0, 1000, GeomFromEWKT('SRID=4326;POINT(0 0)'));
INSERT INTO test4(non_id, manual_id, geom) values (0, -1000, GeomFromEWKT('SRID=4326;POINT(0 0)'));
INSERT INTO test4(non_id, manual_id, geom) values (0, 2147483647, GeomFromEWKT('SRID=4326;POINT(0 0)'));
INSERT INTO test4(non_id, manual_id, geom) values (0, -2147483648, GeomFromEWKT('SRID=4326;POINT(0 0)'));
"""
insert_table_5 = """
CREATE TABLE test5(non_id int4, manual_id numeric PRIMARY KEY, geom geometry);
INSERT INTO test5(non_id, manual_id, geom) values (0, -1, GeomFromEWKT('SRID=4326;POINT(0 0)'));
INSERT INTO test5(non_id, manual_id, geom) values (0, 1, GeomFromEWKT('SRID=4326;POINT(0 0)'));
"""
insert_table_6 = '''
CREATE TABLE "tableWithMixedCase"(gid serial PRIMARY KEY, geom geometry);
INSERT INTO "tableWithMixedCase"(geom) values (ST_MakePoint(0,0));
INSERT INTO "tableWithMixedCase"(geom) values (ST_MakePoint(0,1));
INSERT INTO "tableWithMixedCase"(geom) values (ST_MakePoint(1,0));
INSERT INTO "tableWithMixedCase"(geom) values (ST_MakePoint(1,1));
'''
insert_table_7 = '''
CREATE TABLE test6(first_id int4, second_id int4,PRIMARY KEY (first_id,second_id), geom geometry);
INSERT INTO test6(first_id, second_id, geom) values (0, 0, GeomFromEWKT('SRID=4326;POINT(0 0)'));
'''
insert_table_8 = '''
CREATE TABLE test7(gid serial PRIMARY KEY, geom geometry);
INSERT INTO test7(gid, geom) values (1, GeomFromEWKT('SRID=4326;GEOMETRYCOLLECTION(MULTILINESTRING((10 10,20 20,10 40),(40 40,30 30,40 20,30 10)),LINESTRING EMPTY)'));
'''
def postgis_setup():
call('dropdb %s' % MAPNIK_TEST_DBNAME,silent=True)
call('createdb -T %s %s' % (POSTGIS_TEMPLATE_DBNAME,MAPNIK_TEST_DBNAME),silent=False)
call('shp2pgsql -s 3857 -g geom -W LATIN1 %s world_merc | psql -q %s' % (SHAPEFILE,MAPNIK_TEST_DBNAME), silent=True)
call('''psql -q %s -c "CREATE TABLE \"empty\" (key serial);SELECT AddGeometryColumn('','empty','geom','-1','GEOMETRY',4);"''' % MAPNIK_TEST_DBNAME,silent=False)
call('''psql -q %s -c "%s"''' % (MAPNIK_TEST_DBNAME,insert_table_1),silent=False)
call('''psql -q %s -c "%s"''' % (MAPNIK_TEST_DBNAME,insert_table_2),silent=False)
call('''psql -q %s -c "%s"''' % (MAPNIK_TEST_DBNAME,insert_table_3),silent=False)
call('''psql -q %s -c "%s"''' % (MAPNIK_TEST_DBNAME,insert_table_4),silent=False)
call('''psql -q %s -c "%s"''' % (MAPNIK_TEST_DBNAME,insert_table_5),silent=False)
call("""psql -q %s -c '%s'""" % (MAPNIK_TEST_DBNAME,insert_table_6),silent=False)
call('''psql -q %s -c "%s"''' % (MAPNIK_TEST_DBNAME,insert_table_7),silent=False)
call('''psql -q %s -c "%s"''' % (MAPNIK_TEST_DBNAME,insert_table_8),silent=False)
def postgis_takedown():
pass
# fails as the db is in use: https://github.com/mapnik/mapnik/issues/960
#call('dropdb %s' % MAPNIK_TEST_DBNAME)
if 'postgis' in mapnik.DatasourceCache.instance().plugin_names() \
and createdb_and_dropdb_on_path() \
and psql_can_connect() \
and shp2pgsql_on_path():
# initialize test database
postgis_setup()
def test_feature():
ds = mapnik.PostGIS(dbname=MAPNIK_TEST_DBNAME,table='world_merc')
fs = ds.featureset()
feature = fs.next()
eq_(feature['gid'],1)
eq_(feature['fips'],u'AC')
eq_(feature['iso2'],u'AG')
eq_(feature['iso3'],u'ATG')
eq_(feature['un'],28)
eq_(feature['name'],u'Antigua and Barbuda')
eq_(feature['area'],44)
eq_(feature['pop2005'],83039)
eq_(feature['region'],19)
eq_(feature['subregion'],29)
eq_(feature['lon'],-61.783)
eq_(feature['lat'],17.078)
def test_subquery():
ds = mapnik.PostGIS(dbname=MAPNIK_TEST_DBNAME,table='(select * from world_merc) as w')
fs = ds.featureset()
feature = fs.next()
eq_(feature['gid'],1)
eq_(feature['fips'],u'AC')
eq_(feature['iso2'],u'AG')
eq_(feature['iso3'],u'ATG')
eq_(feature['un'],28)
eq_(feature['name'],u'Antigua and Barbuda')
eq_(feature['area'],44)
eq_(feature['pop2005'],83039)
eq_(feature['region'],19)
eq_(feature['subregion'],29)
eq_(feature['lon'],-61.783)
eq_(feature['lat'],17.078)
ds = mapnik.PostGIS(dbname=MAPNIK_TEST_DBNAME,table='(select gid,geom,fips as _fips from world_merc) as w')
fs = ds.featureset()
feature = fs.next()
eq_(feature['gid'],1)
eq_(feature['_fips'],u'AC')
eq_(len(feature),2)
def test_geometry_detection():
ds = mapnik.PostGIS(dbname=MAPNIK_TEST_DBNAME,table='test',
geometry_field='geom')
def test_disabled_auto_detection_and_subquery():
ds = mapnik.PostGIS(dbname=MAPNIK_TEST_DBNAME,table='''(select geom, 'a'::varchar as name from test2) as t''',
geometry_field='geom')
fs = ds.featureset()
feat = fs.next()
eq_(feat.id(),1)
eq_(feat['name'],'a')
feat = fs.next()
eq_(feat.id(),2)
eq_(feat['name'],'a')
feat = fs.next()
eq_(feat.id(),3)
eq_(feat['name'],'a')
feat = fs.next()
eq_(feat.id(),4)
eq_(feat['name'],'a')
feat = fs.next()
eq_(feat.id(),5)
eq_(feat['name'],'a')
feat = fs.next()
eq_(feat.id(),6)
eq_(feat['name'],'a')
def test_manually_specified_feature_id_field():
ds = mapnik.PostGIS(dbname=MAPNIK_TEST_DBNAME,table='test4',
geometry_field='geom',
key_field='manual_id')
fs = ds.featureset()
eq_(fs.next()['manual_id'],0)
eq_(fs.next()['manual_id'],1)
eq_(fs.next()['manual_id'],1000)
eq_(fs.next()['manual_id'],-1000)
eq_(fs.next()['manual_id'],2147483647)
eq_(fs.next()['manual_id'],-2147483648)
fs = ds.featureset()
eq_(fs.next().id(),0)
eq_(fs.next().id(),1)
eq_(fs.next().id(),1000)
eq_(fs.next().id(),-1000)
eq_(fs.next().id(),2147483647)
eq_(fs.next().id(),-2147483648)
def test_numeric_type_feature_id_field():
ds = mapnik.PostGIS(dbname=MAPNIK_TEST_DBNAME,table='test5',
geometry_field='geom')
fs = ds.featureset()
eq_(fs.next()['manual_id'],-1)
eq_(fs.next()['manual_id'],1)
fs = ds.featureset()
eq_(fs.next().id(),1)
eq_(fs.next().id(),2)
def test_empty_geom():
ds = mapnik.PostGIS(dbname=MAPNIK_TEST_DBNAME,table='test7',
geometry_field='geom')
fs = ds.featureset()
eq_(fs.next()['gid'],1)
atexit.register(postgis_takedown)
if __name__ == "__main__":
setup()
#test_auto_detection_and_subquery()
[eval(run)() for run in dir() if 'test_' in run]

View file

@ -2,22 +2,22 @@
from nose.tools import *
import mapnik2, pickle
import mapnik, pickle
# Tests that exercise map projections.
def test_normalizing_definition():
p = mapnik2.Projection('+init=epsg:4326')
p = mapnik.Projection('+init=epsg:4326')
expanded = p.expanded()
eq_('+proj=longlat' in expanded,True)
# Trac Ticket #128
def test_wgs84_inverse_forward():
p = mapnik2.Projection('+init=epsg:4326')
p = mapnik.Projection('+init=epsg:4326')
c = mapnik2.Coord(3.01331418311, 43.3333092669)
e = mapnik2.Box2d(-122.54345245, 45.12312553, 68.2335581353, 48.231231233)
c = mapnik.Coord(3.01331418311, 43.3333092669)
e = mapnik.Box2d(-122.54345245, 45.12312553, 68.2335581353, 48.231231233)
# It appears that the y component changes very slightly, is this OK?
# so we test for 'almost equal float values'

View file

@ -1,6 +1,6 @@
#coding=utf8
import os
import mapnik2
import mapnik
from utilities import execution_path
from nose.tools import *
@ -14,56 +14,56 @@ def test_gen_map():
mapxmloutputfile = 'raster_colorizer_test_save.xml'
outputfile = 'raster_colorizer_test.png'
m = mapnik2.Map(800, 600)
mapnik2.load_map(m, mapxmlfile)
mapnik2.save_map(m, mapxmloutputfile)
m = mapnik.Map(800, 600)
mapnik.load_map(m, mapxmlfile)
mapnik.save_map(m, mapxmloutputfile)
m.zoom_all()
mapnik2.render_to_file(m, outputfile)
mapnik.render_to_file(m, outputfile)
#test discrete colorizer mode
def test_get_color_discrete():
#setup
colorizer = mapnik2.RasterColorizer();
colorizer.default_color = mapnik2.Color(0,0,0,0);
colorizer.default_mode = mapnik2.COLORIZER_DISCRETE;
colorizer = mapnik.RasterColorizer();
colorizer.default_color = mapnik.Color(0,0,0,0);
colorizer.default_mode = mapnik.COLORIZER_DISCRETE;
colorizer.add_stop(10, mapnik2.Color(100,100,100,100));
colorizer.add_stop(20, mapnik2.Color(200,200,200,200));
colorizer.add_stop(10, mapnik.Color(100,100,100,100));
colorizer.add_stop(20, mapnik.Color(200,200,200,200));
#should be default colour
eq_(colorizer.get_color(-50), mapnik2.Color(0,0,0,0));
eq_(colorizer.get_color(0), mapnik2.Color(0,0,0,0));
eq_(colorizer.get_color(-50), mapnik.Color(0,0,0,0));
eq_(colorizer.get_color(0), mapnik.Color(0,0,0,0));
#now in stop 1
eq_(colorizer.get_color(10), mapnik2.Color(100,100,100,100));
eq_(colorizer.get_color(19), mapnik2.Color(100,100,100,100));
eq_(colorizer.get_color(10), mapnik.Color(100,100,100,100));
eq_(colorizer.get_color(19), mapnik.Color(100,100,100,100));
#now in stop 2
eq_(colorizer.get_color(20), mapnik2.Color(200,200,200,200));
eq_(colorizer.get_color(1000), mapnik2.Color(200,200,200,200));
eq_(colorizer.get_color(20), mapnik.Color(200,200,200,200));
eq_(colorizer.get_color(1000), mapnik.Color(200,200,200,200));
#test exact colorizer mode
def test_get_color_exact():
#setup
colorizer = mapnik2.RasterColorizer();
colorizer.default_color = mapnik2.Color(0,0,0,0);
colorizer.default_mode = mapnik2.COLORIZER_EXACT;
colorizer = mapnik.RasterColorizer();
colorizer.default_color = mapnik.Color(0,0,0,0);
colorizer.default_mode = mapnik.COLORIZER_EXACT;
colorizer.add_stop(10, mapnik2.Color(100,100,100,100));
colorizer.add_stop(20, mapnik2.Color(200,200,200,200));
colorizer.add_stop(10, mapnik.Color(100,100,100,100));
colorizer.add_stop(20, mapnik.Color(200,200,200,200));
#should be default colour
eq_(colorizer.get_color(-50), mapnik2.Color(0,0,0,0));
eq_(colorizer.get_color(11), mapnik2.Color(0,0,0,0));
eq_(colorizer.get_color(20.001), mapnik2.Color(0,0,0,0));
eq_(colorizer.get_color(-50), mapnik.Color(0,0,0,0));
eq_(colorizer.get_color(11), mapnik.Color(0,0,0,0));
eq_(colorizer.get_color(20.001), mapnik.Color(0,0,0,0));
#should be stop 1
eq_(colorizer.get_color(10), mapnik2.Color(100,100,100,100));
eq_(colorizer.get_color(10), mapnik.Color(100,100,100,100));
#should be stop 2
eq_(colorizer.get_color(20), mapnik2.Color(200,200,200,200));
eq_(colorizer.get_color(20), mapnik.Color(200,200,200,200));
@ -71,32 +71,32 @@ def test_get_color_exact():
#test linear colorizer mode
def test_get_color_linear():
#setup
colorizer = mapnik2.RasterColorizer();
colorizer.default_color = mapnik2.Color(0,0,0,0);
colorizer.default_mode = mapnik2.COLORIZER_LINEAR;
colorizer = mapnik.RasterColorizer();
colorizer.default_color = mapnik.Color(0,0,0,0);
colorizer.default_mode = mapnik.COLORIZER_LINEAR;
colorizer.add_stop(10, mapnik2.Color(100,100,100,100));
colorizer.add_stop(20, mapnik2.Color(200,200,200,200));
colorizer.add_stop(10, mapnik.Color(100,100,100,100));
colorizer.add_stop(20, mapnik.Color(200,200,200,200));
#should be default colour
eq_(colorizer.get_color(-50), mapnik2.Color(0,0,0,0));
eq_(colorizer.get_color(9.9), mapnik2.Color(0,0,0,0));
eq_(colorizer.get_color(-50), mapnik.Color(0,0,0,0));
eq_(colorizer.get_color(9.9), mapnik.Color(0,0,0,0));
#should be stop 1
eq_(colorizer.get_color(10), mapnik2.Color(100,100,100,100));
eq_(colorizer.get_color(10), mapnik.Color(100,100,100,100));
#should be stop 2
eq_(colorizer.get_color(20), mapnik2.Color(200,200,200,200));
eq_(colorizer.get_color(20), mapnik.Color(200,200,200,200));
#half way between stops 1 and 2
eq_(colorizer.get_color(15), mapnik2.Color(150,150,150,150));
eq_(colorizer.get_color(15), mapnik.Color(150,150,150,150));
#after stop 2
eq_(colorizer.get_color(100), mapnik2.Color(200,200,200,200));
eq_(colorizer.get_color(100), mapnik.Color(200,200,200,200));
def test_stop_label():
stop = mapnik2.ColorizerStop(1, mapnik2.COLORIZER_LINEAR, mapnik2.Color('red'))
stop = mapnik.ColorizerStop(1, mapnik.COLORIZER_LINEAR, mapnik.Color('red'))
assert not stop.label
label = u"32º C".encode('utf8')
stop.label = label

View file

@ -3,7 +3,7 @@
from nose.tools import *
from utilities import execution_path, save_data, contains_word
import os, mapnik2
import os, mapnik
def setup():
# All of the paths used are relative, if we run the tests
@ -13,19 +13,19 @@ def setup():
def test_dataraster_coloring():
srs = '+init=epsg:32630'
lyr = mapnik2.Layer('dataraster')
lyr.datasource = mapnik2.Gdal(
lyr = mapnik.Layer('dataraster')
lyr.datasource = mapnik.Gdal(
file = '../data/raster/dataraster.tif',
band = 1,
)
lyr.srs = srs
_map = mapnik2.Map(256,256, srs)
style = mapnik2.Style()
rule = mapnik2.Rule()
sym = mapnik2.RasterSymbolizer()
_map = mapnik.Map(256,256, srs)
style = mapnik.Style()
rule = mapnik.Rule()
sym = mapnik.RasterSymbolizer()
# Assigning a colorizer to the RasterSymbolizer tells the later
# that it should use it to colorize the raw data raster
sym.colorizer = mapnik2.RasterColorizer(mapnik2.COLORIZER_DISCRETE, mapnik2.Color("transparent"))
sym.colorizer = mapnik.RasterColorizer(mapnik.COLORIZER_DISCRETE, mapnik.Color("transparent"))
for value, color in [
( 0, "#0044cc"),
@ -40,7 +40,7 @@ def test_dataraster_coloring():
( 90, "#660066"),
( 200, "transparent"),
]:
sym.colorizer.add_stop(value, mapnik2.Color(color))
sym.colorizer.add_stop(value, mapnik.Color(color))
rule.symbols.append(sym)
style.rules.append(rule)
_map.append_style('foo', style)
@ -48,8 +48,8 @@ def test_dataraster_coloring():
_map.layers.append(lyr)
_map.zoom_to_box(lyr.envelope())
im = mapnik2.Image(_map.width,_map.height)
mapnik2.render(_map, im)
im = mapnik.Image(_map.width,_map.height)
mapnik.render(_map, im)
# save a png somewhere so we can see it
save_data('test_dataraster_coloring.png', im.tostring('png'))
imdata = im.tostring()
@ -58,13 +58,13 @@ def test_dataraster_coloring():
def test_dataraster_query_point():
srs = '+init=epsg:32630'
lyr = mapnik2.Layer('dataraster')
lyr.datasource = mapnik2.Gdal(
lyr = mapnik.Layer('dataraster')
lyr.datasource = mapnik.Gdal(
file = '../data/raster/dataraster.tif',
band = 1,
)
lyr.srs = srs
_map = mapnik2.Map(256,256, srs)
_map = mapnik.Map(256,256, srs)
_map.layers.append(lyr)
# point inside raster extent with valid data
@ -86,11 +86,11 @@ def test_dataraster_query_point():
assert len(features) == 0
def test_load_save_map():
map = mapnik2.Map(256,256)
map = mapnik.Map(256,256)
in_map = "../data/good_maps/raster_symbolizer.xml"
mapnik2.load_map(map, in_map)
mapnik.load_map(map, in_map)
out_map = mapnik2.save_map_to_string(map)
out_map = mapnik.save_map_to_string(map)
assert 'RasterSymbolizer' in out_map
assert 'RasterColorizer' in out_map
assert 'stop' in out_map
@ -99,13 +99,13 @@ def test_raster_with_alpha_blends_correctly_with_background():
WIDTH = 500
HEIGHT = 500
map = mapnik2.Map(WIDTH, HEIGHT)
WHITE = mapnik2.Color(255, 255, 255)
map = mapnik.Map(WIDTH, HEIGHT)
WHITE = mapnik.Color(255, 255, 255)
map.background = WHITE
style = mapnik2.Style()
rule = mapnik2.Rule()
symbolizer = mapnik2.RasterSymbolizer()
style = mapnik.Style()
rule = mapnik.Rule()
symbolizer = mapnik.RasterSymbolizer()
#XXX: This fixes it, see http://trac.mapnik.org/ticket/759#comment:3
# (and remove comment when this test passes)
#symbolizer.scaling="bilinear_old"
@ -115,17 +115,17 @@ def test_raster_with_alpha_blends_correctly_with_background():
map.append_style('raster_style', style)
map_layer = mapnik2.Layer('test_layer')
map_layer = mapnik.Layer('test_layer')
filepath = '../data/raster/white-alpha.png'
map_layer.datasource = mapnik2.Gdal(file=filepath)
map_layer.datasource = mapnik.Gdal(file=filepath)
map_layer.styles.append('raster_style')
map.layers.append(map_layer)
map.zoom_all()
mim = mapnik2.Image(WIDTH, HEIGHT)
mim = mapnik.Image(WIDTH, HEIGHT)
mapnik2.render(map, mim)
mapnik.render(map, mim)
save_data('test_raster_with_alpha_blends_correctly_with_background.png',
mim.tostring('png'))
imdata = mim.tostring()
@ -135,27 +135,27 @@ def test_raster_with_alpha_blends_correctly_with_background():
def test_raster_warping():
lyrSrs = "+init=epsg:32630"
mapSrs = '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs'
lyr = mapnik2.Layer('dataraster', lyrSrs)
lyr.datasource = mapnik2.Gdal(
lyr = mapnik.Layer('dataraster', lyrSrs)
lyr.datasource = mapnik.Gdal(
file = '../data/raster/dataraster.tif',
band = 1,
)
sym = mapnik2.RasterSymbolizer()
sym.colorizer = mapnik2.RasterColorizer(mapnik2.COLORIZER_DISCRETE, mapnik2.Color(255,255,0))
rule = mapnik2.Rule()
sym = mapnik.RasterSymbolizer()
sym.colorizer = mapnik.RasterColorizer(mapnik.COLORIZER_DISCRETE, mapnik.Color(255,255,0))
rule = mapnik.Rule()
rule.symbols.append(sym)
style = mapnik2.Style()
style = mapnik.Style()
style.rules.append(rule)
_map = mapnik2.Map(256,256, mapSrs)
_map = mapnik.Map(256,256, mapSrs)
_map.append_style('foo', style)
lyr.styles.append('foo')
_map.layers.append(lyr)
prj_trans = mapnik2.ProjTransform(mapnik2.Projection(mapSrs),
mapnik2.Projection(lyrSrs))
prj_trans = mapnik.ProjTransform(mapnik.Projection(mapSrs),
mapnik.Projection(lyrSrs))
_map.zoom_to_box(prj_trans.backward(lyr.envelope()))
im = mapnik2.Image(_map.width,_map.height)
mapnik2.render(_map, im)
im = mapnik.Image(_map.width,_map.height)
mapnik.render(_map, im)
# save a png somewhere so we can see it
save_data('test_raster_warping.png', im.tostring('png'))
imdata = im.tostring()
@ -164,26 +164,26 @@ def test_raster_warping():
def test_raster_warping_does_not_overclip_source():
lyrSrs = "+init=epsg:32630"
mapSrs = '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs'
lyr = mapnik2.Layer('dataraster', lyrSrs)
lyr.datasource = mapnik2.Gdal(
lyr = mapnik.Layer('dataraster', lyrSrs)
lyr.datasource = mapnik.Gdal(
file = '../data/raster/dataraster.tif',
band = 1,
)
sym = mapnik2.RasterSymbolizer()
sym.colorizer = mapnik2.RasterColorizer(mapnik2.COLORIZER_DISCRETE, mapnik2.Color(255,255,0))
rule = mapnik2.Rule()
sym = mapnik.RasterSymbolizer()
sym.colorizer = mapnik.RasterColorizer(mapnik.COLORIZER_DISCRETE, mapnik.Color(255,255,0))
rule = mapnik.Rule()
rule.symbols.append(sym)
style = mapnik2.Style()
style = mapnik.Style()
style.rules.append(rule)
_map = mapnik2.Map(256,256, mapSrs)
_map.background=mapnik2.Color('white')
_map = mapnik.Map(256,256, mapSrs)
_map.background=mapnik.Color('white')
_map.append_style('foo', style)
lyr.styles.append('foo')
_map.layers.append(lyr)
_map.zoom_to_box(mapnik2.Box2d(3,42,4,43))
_map.zoom_to_box(mapnik.Box2d(3,42,4,43))
im = mapnik2.Image(_map.width,_map.height)
mapnik2.render(_map, im)
im = mapnik.Image(_map.width,_map.height)
mapnik.render(_map, im)
# save a png somewhere so we can see it
save_data('test_raster_warping_does_not_overclip_source.png',
im.tostring('png'))

View file

@ -3,7 +3,7 @@
from nose.tools import *
import os, mapnik2
import os, mapnik
from utilities import Todo
import json
@ -35,31 +35,33 @@ def resolve(grid,x,y):
def create_grid_map(width,height):
places_ds = mapnik2.PointDatasource()
places_ds = mapnik.PointDatasource()
places_ds.add_point(143.10,-38.60,'Name','South East')
places_ds.add_point(142.48,-38.60,'Name','South West')
places_ds.add_point(142.48,-38.38,'Name','North West')
places_ds.add_point(143.10,-38.38,'Name','North East')
s = mapnik2.Style()
r = mapnik2.Rule()
#symb = mapnik2.PointSymbolizer()
symb = mapnik2.MarkersSymbolizer()
s = mapnik.Style()
r = mapnik.Rule()
#symb = mapnik.PointSymbolizer()
symb = mapnik.MarkersSymbolizer()
symb.width = 5
symb.height = 5
symb.allow_overlap = True
r.symbols.append(symb)
label = mapnik2.TextSymbolizer(mapnik2.Expression('[Name]'),
label = mapnik.TextSymbolizer(mapnik.Expression('[Name]'),
'DejaVu Sans Book',
10,
mapnik2.Color('black')
mapnik.Color('black')
)
label.allow_overlap = True
label.displacement = (0,-10)
#r.symbols.append(label)
s.rules.append(r)
lyr = mapnik2.Layer('Places')
lyr = mapnik.Layer('Places')
lyr.datasource = places_ds
lyr.styles.append('places_labels')
m = mapnik2.Map(width,height)
m = mapnik.Map(width,height)
m.append_style('places_labels',s)
m.layers.append(lyr)
return m
@ -68,10 +70,10 @@ def test_render_grid():
""" test old method """
width,height = 256,256
m = create_grid_map(width,height)
ul_lonlat = mapnik2.Coord(142.30,-38.20)
lr_lonlat = mapnik2.Coord(143.40,-38.80)
m.zoom_to_box(mapnik2.Box2d(ul_lonlat,lr_lonlat))
grid = mapnik2.render_grid(m,0,key='Name',resolution=4,fields=['Name'])
ul_lonlat = mapnik.Coord(142.30,-38.20)
lr_lonlat = mapnik.Coord(143.40,-38.80)
m.zoom_to_box(mapnik.Box2d(ul_lonlat,lr_lonlat))
grid = mapnik.render_grid(m,0,key='Name',resolution=4,fields=['Name'])
eq_(grid,grid_correct)
eq_(resolve(grid,0,0),None)
@ -104,18 +106,18 @@ def test_render_grid2():
""" test old against new"""
width,height = 256,256
m = create_grid_map(width,height)
ul_lonlat = mapnik2.Coord(142.30,-38.20)
lr_lonlat = mapnik2.Coord(143.40,-38.80)
m.zoom_to_box(mapnik2.Box2d(ul_lonlat,lr_lonlat))
ul_lonlat = mapnik.Coord(142.30,-38.20)
lr_lonlat = mapnik.Coord(143.40,-38.80)
m.zoom_to_box(mapnik.Box2d(ul_lonlat,lr_lonlat))
# new method
grid = mapnik2.Grid(m.width,m.height,key='Name')
mapnik2.render_layer(m,grid,layer=0,fields=['Name'])
grid = mapnik.Grid(m.width,m.height,key='Name')
mapnik.render_layer(m,grid,layer=0,fields=['Name'])
utf1 = grid.encode('utf',resolution=4)
eq_(utf1,grid_correct_new)
# old method - to be removed
utf2 = mapnik2.render_grid(m,0,key='Name',resolution=4,fields=['Name'])
utf2 = mapnik.render_grid(m,0,key='Name',resolution=4,fields=['Name'])
eq_(utf2,grid_correct)
# for complex polygons these will not be true

View file

@ -3,7 +3,7 @@
from nose.tools import *
import os, mapnik2
import os, mapnik
from nose.tools import *
from utilities import execution_path
@ -16,19 +16,19 @@ def setup():
def test_simplest_render():
m = mapnik2.Map(256, 256)
i = mapnik2.Image(m.width, m.height)
m = mapnik.Map(256, 256)
i = mapnik.Image(m.width, m.height)
mapnik2.render(m, i)
mapnik.render(m, i)
s = i.tostring()
eq_(s, 256 * 256 * '\x00\x00\x00\x00')
def test_render_image_to_string():
i = mapnik2.Image(256, 256)
i = mapnik.Image(256, 256)
i.background = mapnik2.Color('black')
i.background = mapnik.Color('black')
s = i.tostring()
@ -38,24 +38,24 @@ def test_render_image_to_string():
def test_setting_alpha():
w,h = 256,256
im1 = mapnik2.Image(w,h)
im1 = mapnik.Image(w,h)
# white, half transparent
im1.background = mapnik2.Color('rgba(255,255,255,.5)')
im1.background = mapnik.Color('rgba(255,255,255,.5)')
# pure white
im2 = mapnik2.Image(w,h)
im2.background = mapnik2.Color('rgba(255,255,255,1)')
im2 = mapnik.Image(w,h)
im2.background = mapnik.Color('rgba(255,255,255,1)')
im2.set_alpha(.5)
eq_(len(im1.tostring()), len(im2.tostring()))
def test_render_image_to_file():
i = mapnik2.Image(256, 256)
i = mapnik.Image(256, 256)
i.background = mapnik2.Color('black')
i.background = mapnik.Color('black')
if mapnik2.has_jpeg():
if mapnik.has_jpeg():
i.save('test.jpg')
i.save('test.png', 'png')
@ -71,17 +71,17 @@ def test_render_image_to_file():
def get_paired_images(w,h,mapfile):
tmp_map = 'tmp_map.xml'
m = mapnik2.Map(w,h)
mapnik2.load_map(m,mapfile)
i = mapnik2.Image(w,h)
m = mapnik.Map(w,h)
mapnik.load_map(m,mapfile)
i = mapnik.Image(w,h)
m.zoom_all()
mapnik2.render(m,i)
mapnik2.save_map(m,tmp_map)
m2 = mapnik2.Map(w,h)
mapnik2.load_map(m2,tmp_map)
i2 = mapnik2.Image(w,h)
mapnik.render(m,i)
mapnik.save_map(m,tmp_map)
m2 = mapnik.Map(w,h)
mapnik.load_map(m2,tmp_map)
i2 = mapnik.Image(w,h)
m2.zoom_all()
mapnik2.render(m2,i2)
mapnik.render(m2,i2)
os.remove(tmp_map)
return i,i2
@ -118,37 +118,39 @@ def resolve(grid,x,y):
def test_render_grid():
places_ds = mapnik2.PointDatasource()
places_ds = mapnik.PointDatasource()
places_ds.add_point(143.10,-38.60,'Name','South East')
places_ds.add_point(142.48,-38.60,'Name','South West')
places_ds.add_point(142.48,-38.38,'Name','North West')
places_ds.add_point(143.10,-38.38,'Name','North East')
s = mapnik2.Style()
r = mapnik2.Rule()
#symb = mapnik2.PointSymbolizer()
symb = mapnik2.MarkersSymbolizer()
s = mapnik.Style()
r = mapnik.Rule()
#symb = mapnik.PointSymbolizer()
symb = mapnik.MarkersSymbolizer()
symb.width = 5
symb.height = 5
symb.allow_overlap = True
r.symbols.append(symb)
label = mapnik2.TextSymbolizer(mapnik2.Expression('[Name]'),
label = mapnik.TextSymbolizer(mapnik.Expression('[Name]'),
'DejaVu Sans Book',
10,
mapnik2.Color('black')
mapnik.Color('black')
)
label.allow_overlap = True
label.displacement = (0,-10)
#r.symbols.append(label)
s.rules.append(r)
lyr = mapnik2.Layer('Places')
lyr = mapnik.Layer('Places')
lyr.datasource = places_ds
lyr.styles.append('places_labels')
m = mapnik2.Map(256,256)
m = mapnik.Map(256,256)
m.append_style('places_labels',s)
m.layers.append(lyr)
ul_lonlat = mapnik2.Coord(142.30,-38.20)
lr_lonlat = mapnik2.Coord(143.40,-38.80)
m.zoom_to_box(mapnik2.Box2d(ul_lonlat,lr_lonlat))
grid = mapnik2.render_grid(m,0,key='Name',resolution=4,fields=['Name'])
ul_lonlat = mapnik.Coord(142.30,-38.20)
lr_lonlat = mapnik.Coord(143.40,-38.80)
m.zoom_to_box(mapnik.Box2d(ul_lonlat,lr_lonlat))
grid = mapnik.render_grid(m,0,key='Name',resolution=4,fields=['Name'])
eq_(grid,grid_correct)
eq_(resolve(grid,0,0),None)
@ -179,25 +181,25 @@ def test_render_grid():
def test_render_points():
if not mapnik2.has_cairo(): return
if not mapnik.has_cairo(): return
# create and populate point datasource (WGS84 lat-lon coordinates)
places_ds = mapnik2.PointDatasource()
places_ds = mapnik.PointDatasource()
places_ds.add_point(142.48,-38.38,'Name','Westernmost Point') # westernmost
places_ds.add_point(143.10,-38.60,'Name','Southernmost Point') # southernmost
# create layer/rule/style
s = mapnik2.Style()
r = mapnik2.Rule()
symb = mapnik2.PointSymbolizer()
s = mapnik.Style()
r = mapnik.Rule()
symb = mapnik.PointSymbolizer()
symb.allow_overlap = True
r.symbols.append(symb)
s.rules.append(r)
lyr = mapnik2.Layer('Places','+proj=latlon +datum=WGS84')
lyr = mapnik.Layer('Places','+proj=latlon +datum=WGS84')
lyr.datasource = places_ds
lyr.styles.append('places_labels')
# latlon bounding box corners
ul_lonlat = mapnik2.Coord(142.30,-38.20)
lr_lonlat = mapnik2.Coord(143.40,-38.80)
ul_lonlat = mapnik.Coord(142.30,-38.20)
lr_lonlat = mapnik.Coord(143.40,-38.80)
# render for different projections
projs = {
'latlon': '+proj=latlon +datum=WGS84',
@ -206,14 +208,14 @@ def test_render_points():
'utm': '+proj=utm +zone=54 +datum=WGS84'
}
for projdescr in projs.iterkeys():
m = mapnik2.Map(1000, 500, projs[projdescr])
m = mapnik.Map(1000, 500, projs[projdescr])
m.append_style('places_labels',s)
m.layers.append(lyr)
p = mapnik2.Projection(projs[projdescr])
m.zoom_to_box(p.forward(mapnik2.Box2d(ul_lonlat,lr_lonlat)))
p = mapnik.Projection(projs[projdescr])
m.zoom_to_box(p.forward(mapnik.Box2d(ul_lonlat,lr_lonlat)))
# Render to SVG so that it can be checked how many points are there with string comparison
svg_file = '/tmp/%s.svg'
mapnik2.render_to_file(m, svg_file)
mapnik.render_to_file(m, svg_file)
num_points_present = len(places_ds.all_features())
svg = open(svg_file,'r').read()
num_points_rendered = svg.count('<image ')

View file

@ -5,7 +5,7 @@ from utilities import Todo
from utilities import execution_path
import tempfile
import os, sys, glob, mapnik2
import os, sys, glob, mapnik
def setup():
# All of the paths used are relative, if we run the tests
@ -18,13 +18,13 @@ def test():
# 2. Save map as XML
# 3. Load map to a second object
# 4. Compare both map objects
map = mapnik2.Map(256, 256)
map = mapnik.Map(256, 256)
raise Todo("map comparison is currently broken due to lacking relative paths support (#324,#340")
def compare_map(in_map):
mapnik2.load_map(map, in_map)
mapnik.load_map(map, in_map)
(handle, test_map) = tempfile.mkstemp(suffix='.xml', prefix='mapnik-temp-map1-')
os.close(handle)
@ -35,11 +35,11 @@ def test():
if os.path.exists(test_map):
os.remove(test_map)
mapnik2.save_map(map, test_map)
new_map = mapnik2.Map(256, 256)
mapnik.save_map(map, test_map)
new_map = mapnik.Map(256, 256)
mapnik2.load_map(new_map, test_map)
open(test_map2,'w').write(mapnik2.save_map_to_string(new_map))
mapnik.load_map(new_map, test_map)
open(test_map2,'w').write(mapnik.save_map_to_string(new_map))
diff = ' diff %s %s' % (os.path.abspath(test_map),os.path.abspath(test_map2))
try:

View file

@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
import sys
import os, mapnik2
import os, mapnik
from timeit import Timer, time
from nose.tools import *
from utilities import execution_path
@ -59,7 +59,7 @@ def do_encoding():
def blank():
eval('image.tostring("%s")' % c)
blank_im = mapnik2.Image(512,512)
blank_im = mapnik.Image(512,512)
for c in combinations:
t = Timer(blank)
@ -67,8 +67,8 @@ def do_encoding():
def solid():
eval('image.tostring("%s")' % c)
solid_im = mapnik2.Image(512,512)
solid_im.background = mapnik2.Color("#f2efe9")
solid_im = mapnik.Image(512,512)
solid_im.background = mapnik.Color("#f2efe9")
for c in combinations:
t = Timer(solid)
@ -77,7 +77,7 @@ def do_encoding():
def many_colors():
eval('image.tostring("%s")' % c)
# lots of colors: http://tile.osm.org/13/4194/2747.png
many_colors_im = mapnik2.Image.open('../data/images/13_4194_2747.png')
many_colors_im = mapnik.Image.open('../data/images/13_4194_2747.png')
for c in combinations:
t = Timer(many_colors)

View file

@ -3,7 +3,7 @@
from nose.tools import *
from utilities import execution_path
import os, mapnik2
import os, mapnik
def setup():
# All of the paths used are relative, if we run the tests
@ -17,13 +17,13 @@ def setup():
def test_attachdb_with_relative_file():
# The point table and index is in the qgis_spatiallite.sqlite
# database. If either is not found, then this fails
ds = mapnik2.SQLite(file='../data/sqlite/world.sqlite',
ds = mapnik.SQLite(file='../data/sqlite/world.sqlite',
table='point',
attachdb='scratch@qgis_spatiallite.sqlite'
)
def test_attachdb_with_multiple_files():
ds = mapnik2.SQLite(file='../data/sqlite/world.sqlite',
ds = mapnik.SQLite(file='../data/sqlite/world.sqlite',
table='attachedtest',
attachdb='scratch1@:memory:,scratch2@:memory:',
initdb='create table scratch1.attachedtest (the_geom);\n' +
@ -34,13 +34,13 @@ def test_attachdb_with_multiple_files():
def test_attachdb_with_absolute_file():
# The point table and index is in the qgis_spatiallite.sqlite
# database. If either is not found, then this fails
ds = mapnik2.SQLite(file=os.getcwd() + '/../data/sqlite/world.sqlite',
ds = mapnik.SQLite(file=os.getcwd() + '/../data/sqlite/world.sqlite',
table='point',
attachdb='scratch@qgis_spatiallite.sqlite'
)
def test_attachdb_with_index():
ds = mapnik2.SQLite(file='../data/sqlite/world.sqlite',
ds = mapnik.SQLite(file='../data/sqlite/world.sqlite',
table='attachedtest',
attachdb='scratch@:memory:',
initdb='create table scratch.attachedtest (the_geom);\n' +
@ -49,7 +49,7 @@ def test_attachdb_with_index():
)
def test_attachdb_with_explicit_index():
ds = mapnik2.SQLite(file='../data/sqlite/world.sqlite',
ds = mapnik.SQLite(file='../data/sqlite/world.sqlite',
table='attachedtest',
index_table='myindex',
attachdb='scratch@:memory:',

View file

@ -42,14 +42,14 @@ def main():
# Allow python to find libraries for testing on the buildbot
sys.path.insert(0, os.path.join(prefix, "lib/python%s/site-packages" % sys.version[:3]))
import mapnik2
import mapnik
if not quiet:
print("- mapnik2 path: %s" % mapnik2.__file__)
if hasattr(mapnik2,'_mapnik2'):
print("- _mapnik2.so path: %s" % mapnik2._mapnik2.__file__)
print("- Input plugins path: %s" % mapnik2.inputpluginspath)
print("- Font path: %s" % mapnik2.fontscollectionpath)
print("- mapnik path: %s" % mapnik.__file__)
if hasattr(mapnik,'_mapnik'):
print("- _mapnik.so path: %s" % mapnik._mapnik.__file__)
print("- Input plugins path: %s" % mapnik.inputpluginspath)
print("- Font path: %s" % mapnik.fontscollectionpath)
print('')
print("- Running nosetests:")
print('')

View file

@ -1,6 +1,6 @@
#!/bin/sh
API_DOCS_DIR="../api_docs/python"
API_DOCS_DIR="mapnik-python-`mapnik-config --version`"
if [ ! -d $API_DOCS_DIR ]
then
@ -11,9 +11,9 @@ fi
epydoc --no-private \
--no-frames \
--no-sourcecode \
--name mapnik2 \
--name mapnik \
--url http://mapnik.org \
--css mapnik_epydoc.css mapnik2 \
--css mapnik_epydoc.css mapnik \
-o $API_DOCS_DIR
exit $?

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