diff --git a/CHANGELOG b/CHANGELOG index ba2380754..49aa4e399 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -14,6 +14,8 @@ For a complete change history, see the SVN log. Mapnik 2.1.0 ------------ +- SQLite - Added support for !intersects! token in sql subselects (#809) allow custom positioning of rtree spatial filter. + - New CSV plugin - reads tabular files - autodetecting geo columns, newlines, and delimiters. Uses in-memory featureset for fast rendering and is not designed for large files (#902) - Fixed bug in shield line placement when dx/dy are used to shift the label relative to the placement point (Matt Amos) (#908) diff --git a/INSTALL.md b/INSTALL.md index c06daa12a..386d6afd3 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -36,12 +36,17 @@ Build dependencies are: Mapnik Core depends on: - * Boost >= 1.42.x (>= 1.45.x if using clang++) with these libraries: - - filesystem - - system - - thread (if mapnik threadsafe support is required, default on) - - regex (optionally built with icu regex support) - - program_options (optionally for mapnik command line programs) + * Boost + - >= 1.46 is recommended + - >= 1.45 is required if compiling with clang++ + - >= 1.42 works on most systems and most compilers + - >= 1.47 is required to support wkt/wkb geometry output (optional) + - These libraries are required: + - filesystem + - system + - thread (if mapnik threadsafe support is required, default on) + - regex (optionally built with icu regex support) + - program_options (optionally for mapnik command line programs) * libicuuc >= 4.0 (ideally >= 4.2) - International Components for Unicode * libpng >= 1.2.x - PNG Graphics diff --git a/Makefile b/Makefile index 73e45ffd8..a9bd8775b 100755 --- a/Makefile +++ b/Makefile @@ -12,6 +12,7 @@ clean: reset: if test -e ".sconf_temp/"; then rm -r ".sconf_temp/"; fi if test -e ".sconsign.dblite"; then rm ".sconsign.dblite"; fi + if test -e "config.cache"; then rm "config.cache"; fi uninstall: python scons/scons.py uninstall diff --git a/SConstruct b/SConstruct index cae93d64b..256508aa7 100644 --- a/SConstruct +++ b/SConstruct @@ -424,7 +424,8 @@ pickle_store = [# Scons internal variables 'CAIROMM_LINKFLAGS', 'CAIROMM_CPPPATHS', 'SVG_RENDERER', - 'SQLITE_LINKFLAGS' + 'SQLITE_LINKFLAGS', + 'BOOST_LIB_VERSION_FROM_HEADER' ] # Add all other user configurable options to pickle pickle_store @@ -1115,10 +1116,7 @@ if not preconfigured: conf.FindBoost(BOOST_SEARCH_PREFIXES,thread_flag) - 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() # The other required boost headers. BOOST_LIBSHEADERS = [ @@ -1148,7 +1146,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.get('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++'): @@ -1432,8 +1430,9 @@ if not preconfigured: env.Append(CXXFLAGS = gcc_cxx_flags + '-O0 -fno-inline %s' % debug_flags) else: env.Append(CXXFLAGS = gcc_cxx_flags + '-O%s -finline-functions -Wno-inline -Wno-parentheses -Wno-char-subscripts %s' % (env['OPTIMIZATION'],ndebug_flags)) + if env['DEBUG_UNDEFINED']: - env.Append(CXXFLAGS = '-fcatch-undefined-behavior') #-ftrapv -fwrapv + env.Append(CXXFLAGS = '-fcatch-undefined-behavior') #-ftrapv -fwrapv if 'python' in env['BINDINGS']: if not os.access(env['PYTHON'], os.X_OK): diff --git a/bindings/python/build.py b/bindings/python/build.py index 5a3c4af98..7ad2385a1 100644 --- a/bindings/python/build.py +++ b/bindings/python/build.py @@ -41,11 +41,9 @@ def is_py3(): prefix = env['PREFIX'] target_path = os.path.normpath(env['PYTHON_INSTALL_LOCATION'] + os.path.sep + 'mapnik') +target_path_deprecated = os.path.normpath(env['PYTHON_INSTALL_LOCATION'] + os.path.sep + 'mapnik2') -libraries = ['mapnik','png'] - -if env['JPEG']: - libraries.append('jpeg') +libraries = ['mapnik'] if env['BOOST_PYTHON_LIB']: libraries.append(env['BOOST_PYTHON_LIB']) @@ -55,11 +53,16 @@ else: 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: @@ -105,6 +108,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 @@ -121,22 +125,28 @@ 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'])) + +if hasattr(os.path,'relpath'): # python 2.6 and above + file('mapnik/paths.py','w').write(paths % (os.path.relpath(env['MAPNIK_LIB_DIR'],target_path))) +else: + file('mapnik/paths.py','w').write(paths % (env['MAPNIK_LIB_DIR'])) # force open perms temporarily so that `sudo scons install` # does not later break simple non-install non-sudo rebuild @@ -152,8 +162,7 @@ if 'install' in COMMAND_LINE_TARGETS: 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 - path = os.path.normpath(env['PYTHON_INSTALL_LOCATION'] + os.path.sep + 'mapnik2') - init_mapnik2 = env.Install(path, 'mapnik2/__init__.py') + 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' @@ -204,4 +213,5 @@ if 'uninstall' not in COMMAND_LINE_TARGETS: env['create_uninstall_target'](env, target_path) +env['create_uninstall_target'](env, target_path_deprecated) diff --git a/bindings/python/mapnik/__init__.py b/bindings/python/mapnik/__init__.py index 49744a53e..c308fbfd4 100644 --- a/bindings/python/mapnik/__init__.py +++ b/bindings/python/mapnik/__init__.py @@ -381,7 +381,6 @@ def PostGIS(**keywords): srid -- specify srid to use (default: auto-detected from geometry_field) row_limit -- integer limit of rows to return (default: 0) cursor_size -- integer size of binary cursor to use (default: 0, no binary cursor is used) - multiple_geometries -- boolean, direct the Mapnik wkb reader to interpret as multigeometries (default False) >>> from mapnik import PostGIS, Layer >>> params = dict(dbname='mapnik',table='osm',user='postgres',password='gis') @@ -467,7 +466,6 @@ def Occi(**keywords): encoding -- file encoding (default 'utf-8') geometry_field -- specify geometry field (default 'GEOLOC') use_spatial_index -- boolean, force the use of the spatial index (default True) - multiple_geometries -- boolean, direct the Mapnik wkb reader to interpret as multigeometries (default False) >>> from mapnik import Occi, Layer >>> params = dict(host='myoracle',user='scott',password='tiger',table='test') @@ -492,7 +490,6 @@ def Ogr(**keywords): layer_by_sql -- choose layer by sql query number instead of by layer name or index. base -- path prefix (default None) encoding -- file encoding (default 'utf-8') - multiple_geometries -- boolean, direct the Mapnik wkb reader to interpret as multigeometries (default False) >>> from mapnik import Ogr, Layer >>> datasource = Ogr(base='/home/mapnik/data',file='rivers.geojson',layer='OGRGeoJSON') @@ -520,7 +517,6 @@ def SQLite(**keywords): row_offset -- specify a custom integer row offset (default 0) row_limit -- specify a custom integer row limit (default 0) wkb_format -- specify a wkb type of 'spatialite' (default None) - multiple_geometries -- boolean, direct the Mapnik wkb reader to interpret as multigeometries (default False) use_spatial_index -- boolean, instruct sqlite plugin to use Rtree spatial index (default True) >>> from mapnik import SQLite, Layer @@ -601,7 +597,6 @@ def Geos(**keywords): wkt -- inline WKT text of the geometry Optional keyword arguments: - multiple_geometries -- boolean, direct the GEOS wkt reader to interpret as multigeometries (default False) extent -- manually specified data extent (comma delimited string, default None) >>> from mapnik import Geos, Layer @@ -655,6 +650,7 @@ __all__ = [ 'Feature', 'Featureset', 'FontEngine', + 'FontSet', 'Geometry2d', 'GlyphSymbolizer', 'Image', diff --git a/bindings/python/mapnik/paths.py.in b/bindings/python/mapnik/paths.py.in deleted file mode 100644 index 0100d6a83..000000000 --- a/bindings/python/mapnik/paths.py.in +++ /dev/null @@ -1,3 +0,0 @@ -mapniklibpath = '@PACKAGE_LIB_DIR@' -inputpluginspath = mapniklibpath + '/input' -fontscollectionpath = '@SYSTEM_FONTS_DIR@/truetype/ttf-dejavu' diff --git a/bindings/python/mapnik/printing.py b/bindings/python/mapnik/printing.py index 58f18b653..5e6456bd9 100644 --- a/bindings/python/mapnik/printing.py +++ b/bindings/python/mapnik/printing.py @@ -593,7 +593,7 @@ class PDFPrinter: for l in m.layers: # extract the layer names for naming layers if we use OCG - self._layer_names.append(l.title or l.name) + self._layer_names.append(l.name) layer_map = Map(m.width,m.height,m.srs) layer_map.layers.append(l) @@ -884,7 +884,7 @@ class PDFPrinter: for l in reversed(m.layers): have_layer_header = False added_styles={} - layer_title = l.title or l.name + layer_title = l.name if layer_title in processed_layers: continue processed_layers.append(layer_title) @@ -906,8 +906,8 @@ class PDFPrinter: if r.filter and str(r.filter) != "true": if len(rule_text) > 0: rule_text += " AND " - if r.title: - rule_text += r.title + if r.name: + rule_text += r.name else: rule_text += str(r.filter) active_rules = tuple(active_rules) diff --git a/bindings/python/mapnik_envelope.cpp b/bindings/python/mapnik_envelope.cpp index 85f74bf9a..9cae79b2f 100644 --- a/bindings/python/mapnik_envelope.cpp +++ b/bindings/python/mapnik_envelope.cpp @@ -87,6 +87,14 @@ void (box2d::*re_center_p2)(coord const& ) = &box2d::r // clip void (box2d::*clip)(box2d const&) = &box2d::clip; +// deepcopy +box2d box2d_deepcopy(box2d & obj, boost::python::dict memo) +{ + // FIXME::ignore memo for now + box2d result(obj); + return result; +} + void export_envelope() { using namespace boost::python; @@ -270,5 +278,7 @@ void export_envelope() .def("__getitem__",&box2d::operator[]) .def("valid",&box2d::valid) .def_pickle(envelope_pickle_suite()) + .def("__deepcopy__", &box2d_deepcopy) ; + } diff --git a/bindings/python/mapnik_feature.cpp b/bindings/python/mapnik_feature.cpp index 57cdec88c..4bc392af4 100644 --- a/bindings/python/mapnik_feature.cpp +++ b/bindings/python/mapnik_feature.cpp @@ -45,7 +45,7 @@ using mapnik::from_wkt; void feature_add_geometries_from_wkb(Feature &feature, std::string wkb) { - geometry_utils::from_wkb(feature.paths(), wkb.c_str(), wkb.size(), true); + geometry_utils::from_wkb(feature.paths(), wkb.c_str(), wkb.size()); } void feature_add_geometries_from_wkt(Feature &feature, std::string wkt) diff --git a/bindings/python/mapnik_fontset.cpp b/bindings/python/mapnik_fontset.cpp new file mode 100644 index 000000000..c4951ba94 --- /dev/null +++ b/bindings/python/mapnik_fontset.cpp @@ -0,0 +1,61 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2011 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ + + +// boost +#include + +//mapnik +#include + + +using mapnik::font_set; + +struct fontset_pickle_suite : boost::python::pickle_suite +{ + static boost::python::tuple + getinitargs(const font_set& fs) + { + return boost::python::make_tuple(fs.get_name()); + } +}; + +void export_fontset () +{ + using namespace boost::python; + class_("FontSet", init<>("default fontset constructor") + ) + .def_pickle(fontset_pickle_suite()) + .def("add_face_name",&font_set::add_face_name, + (arg("name")), + "Add a face-name to the fontset.\n" + "\n" + "Example:\n" + ">>> fs = Fontset('book-fonts')\n" + ">>> fs.add_face_name('DejaVu Sans Book')\n") + .add_property("names",make_function + (&font_set::get_face_names, + return_value_policy()), + "List of face names belonging to a FontSet.\n" + ) + ; +} diff --git a/bindings/python/mapnik_geometry.cpp b/bindings/python/mapnik_geometry.cpp index 516c5fc90..2a3e74ee1 100644 --- a/bindings/python/mapnik_geometry.cpp +++ b/bindings/python/mapnik_geometry.cpp @@ -26,13 +26,18 @@ #include #include #include +#include // mapnik #include #include #include + +#include +#if BOOST_VERSION >= 104700 #include #include +#endif namespace { @@ -57,7 +62,7 @@ void add_wkt_impl(path_type& p, std::string const& wkt) void add_wkb_impl(path_type& p, std::string const& wkb) { - mapnik::geometry_utils::from_wkb(p, wkb.c_str(), wkb.size(), true); + mapnik::geometry_utils::from_wkb(p, wkb.c_str(), wkb.size()); } boost::shared_ptr from_wkt_impl(std::string const& wkt) @@ -71,15 +76,23 @@ boost::shared_ptr from_wkt_impl(std::string const& wkt) boost::shared_ptr from_wkb_impl(std::string const& wkb) { boost::shared_ptr paths = boost::make_shared(); - mapnik::geometry_utils::from_wkb(*paths, wkb.c_str(), wkb.size(), true); + mapnik::geometry_utils::from_wkb(*paths, wkb.c_str(), wkb.size()); return paths; } } -PyObject* to_wkb( geometry_type const& geom) +inline std::string boost_version() { - mapnik::util::wkb_buffer_ptr wkb = mapnik::util::to_wkb(geom,mapnik::util::wkbXDR); + std::ostringstream s; + s << BOOST_VERSION/100000 << "." << BOOST_VERSION/100 % 1000 << "." << BOOST_VERSION % 100; + return s.str(); +} + +#if BOOST_VERSION >= 104700 +PyObject* to_wkb( geometry_type const& geom, mapnik::util::wkbByteOrder byte_order) +{ + mapnik::util::wkb_buffer_ptr wkb = mapnik::util::to_wkb(geom,byte_order); return #if PY_VERSION_HEX >= 0x03000000 ::PyBytes_FromStringAndSize @@ -88,9 +101,39 @@ PyObject* to_wkb( geometry_type const& geom) #endif ((const char*)wkb->buffer(),wkb->size()); } +#else +PyObject* to_wkb( geometry_type const& geom) +{ + throw std::runtime_error("mapnik::to_wkb() requires at least boost 1.47 while your build was compiled against boost " + + boost_version()); +} +#endif + + +#if BOOST_VERSION >= 104700 +PyObject* to_wkb2( path_type const& p, mapnik::util::wkbByteOrder byte_order) +{ + mapnik::util::wkb_buffer_ptr wkb = mapnik::util::to_wkb(p,byte_order); + return +#if PY_VERSION_HEX >= 0x03000000 + ::PyBytes_FromStringAndSize +#else + ::PyString_FromStringAndSize +#endif + ((const char*)wkb->buffer(),wkb->size()); +} +#else +PyObject* to_wkb2( path_type const& p) +{ + throw std::runtime_error("mapnik::to_wkb() requires at least boost 1.47 while your build was compiled against boost " + + boost_version()); +} +#endif + std::string to_wkt( geometry_type const& geom) { +#if BOOST_VERSION >= 104700 std::string wkt; // Use Python String directly ? bool result = mapnik::util::to_wkt(wkt,geom); if (!result) @@ -98,8 +141,29 @@ std::string to_wkt( geometry_type const& geom) throw std::runtime_error("Generate WKT failed"); } return wkt; +#else + throw std::runtime_error("mapnik::to_wkt() requires at least boost 1.47 while your build was compiled against boost " + + boost_version()); +#endif } +std::string to_wkt2( path_type const& geom) +{ +#if BOOST_VERSION >= 104700 + std::string wkt; // Use Python String directly ? + bool result = mapnik::util::to_wkt(wkt,geom); + if (!result) + { + throw std::runtime_error("Generate WKT failed"); + } + return wkt; +#else + throw std::runtime_error("mapnik::to_wkt() requires at least boost 1.47 while your build was compiled against boost " + + boost_version()); +#endif +} + + void export_geometry() { using namespace boost::python; @@ -108,11 +172,15 @@ void export_geometry() .value("Point",mapnik::Point) .value("LineString",mapnik::LineString) .value("Polygon",mapnik::Polygon) - .value("MultiPoint",mapnik::MultiPoint) - .value("MultiLineString",mapnik::MultiLineString) - .value("MultiPolygon",mapnik::MultiPolygon) ; +#if BOOST_VERSION >= 104700 + enum_("wkbByteOrder") + .value("XDR",mapnik::util::wkbXDR) + .value("NDR",mapnik::util::wkbNDR) + ; +#endif + using mapnik::geometry_type; class_, boost::noncopyable>("Geometry2d",no_init) .def("envelope",&geometry_type::envelope) @@ -128,6 +196,8 @@ void export_geometry() .def("__len__", &path_type::size) .def("add_wkt",add_wkt_impl) .def("add_wkb",add_wkb_impl) + .def("to_wkt",&to_wkt2) + .def("to_wkb",&to_wkb2) .def("from_wkt",from_wkt_impl) .def("from_wkb",from_wkb_impl) .staticmethod("from_wkt") diff --git a/bindings/python/mapnik_layer.cpp b/bindings/python/mapnik_layer.cpp index 916f8f602..a37843b7f 100644 --- a/bindings/python/mapnik_layer.cpp +++ b/bindings/python/mapnik_layer.cpp @@ -54,7 +54,7 @@ struct layer_pickle_suite : boost::python::pickle_suite { s.append(style_names[i]); } - return boost::python::make_tuple(l.abstract(),l.title(),l.clear_label_cache(),l.getMinZoom(),l.getMaxZoom(),l.isQueryable(),l.datasource()->params(),l.cache_features(),s); + return boost::python::make_tuple(l.clear_label_cache(),l.getMinZoom(),l.getMaxZoom(),l.isQueryable(),l.datasource()->params(),l.cache_features(),s); } static void @@ -70,28 +70,24 @@ struct layer_pickle_suite : boost::python::pickle_suite throw_error_already_set(); } - l.set_abstract(extract(state[0])); + l.set_clear_label_cache(extract(state[0])); - l.set_title(extract(state[1])); + l.setMinZoom(extract(state[1])); - l.set_clear_label_cache(extract(state[2])); + l.setMaxZoom(extract(state[2])); - l.setMinZoom(extract(state[3])); + l.setQueryable(extract(state[3])); - l.setMaxZoom(extract(state[4])); - - l.setQueryable(extract(state[5])); - - mapnik::parameters params = extract(state[6]); + mapnik::parameters params = extract(state[4]); l.set_datasource(datasource_cache::instance()->create(params)); - boost::python::list s = extract(state[7]); + boost::python::list s = extract(state[5]); for (int i=0;i(s[i])); } - l.set_cache_features(extract(state[8])); + l.set_cache_features(extract(state[6])); } }; @@ -152,21 +148,6 @@ void export_layer() "False\n" ) - .add_property("abstract", - make_function(&layer::abstract,return_value_policy()), - &layer::set_abstract, - "Get/Set the abstract of the layer.\n" - "\n" - "Usage:\n" - ">>> from mapnik import Layer\n" - ">>> lyr = Layer('My Layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n" - ">>> lyr.abstract\n" - "'' # default is en empty string\n" - ">>> lyr.abstract = 'My Shapefile rendered with Mapnik'\n" - ">>> lyr.abstract\n" - "'My Shapefile rendered with Mapnik'\n" - ) - .add_property("active", &layer::isActive, &layer::setActive, @@ -310,20 +291,5 @@ void export_layer() "'My Style'\n" ) - .add_property("title", - make_function(&layer::title, return_value_policy()), - &layer::set_title, - "Get/Set the title of the layer.\n" - "\n" - "Usage:\n" - ">>> from mapnik import layer\n" - ">>> lyr = layer('My layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n" - ">>> lyr.title\n" - "''\n" - ">>> lyr.title = 'My first layer'\n" - ">>> lyr.title\n" - "'My first layer'\n" - ) - ; } diff --git a/bindings/python/mapnik_map.cpp b/bindings/python/mapnik_map.cpp index a51b26e9f..a947eeef8 100644 --- a/bindings/python/mapnik_map.cpp +++ b/bindings/python/mapnik_map.cpp @@ -31,7 +31,7 @@ #include #include #include - +#include #include "mapnik_enumeration.hpp" #include "python_optional.hpp" @@ -122,7 +122,8 @@ std::vector const& (Map::*layers_const)() const = &Map::layers; mapnik::parameters& (Map::*attr_nonconst)() = &Map::get_extra_attributes; mapnik::parameters& (Map::*params_nonconst)() = &Map::get_extra_parameters; -mapnik::feature_type_style find_style (mapnik::Map const& m, std::string const& name) + +mapnik::feature_type_style find_style(mapnik::Map const& m, std::string const& name) { boost::optional style = m.find_style(name); if (!style) @@ -133,6 +134,17 @@ mapnik::feature_type_style find_style (mapnik::Map const& m, std::string const& return *style; } +mapnik::font_set find_fontset(mapnik::Map const& m, std::string const& name) +{ + boost::optional fontset = m.find_fontset(name); + if (!fontset) + { + PyErr_SetString(PyExc_KeyError, "Invalid font_set name"); + boost::python::throw_error_already_set(); + } + return *fontset; +} + bool has_metawriter(mapnik::Map const& m) { if (m.metawriters().size() >=1) @@ -175,6 +187,15 @@ mapnik::featureset_ptr query_map_point(mapnik::Map const& m, int index, double x return m.query_map_point(idx, x, y); } +// deepcopy +mapnik::Map map_deepcopy(mapnik::Map & m, boost::python::dict memo) +{ + // FIXME: ignore memo for now + mapnik::Map result; + mapnik::util::deepcopy(m, result); + return result; +} + void export_map() { @@ -193,6 +214,7 @@ void export_map() ; python_optional (); + python_optional > (); class_ >("Layers") .def(vector_indexing_suite >()) ; @@ -229,6 +251,11 @@ void export_map() "False # you can only append styles with unique names\n" ) + .def("append_fontset",&Map::insert_fontset, + (arg("fontset")), + "Add a FontSet to the map." + ) + .def("buffered_envelope", &Map::get_buffered_extent, "Get the Box2d() of the Map given\n" @@ -261,9 +288,14 @@ void export_map() "...'maxy', 'minx', 'miny', 'width'\n" ) + .def("find_fontset",find_fontset, + (arg("name")), + "Find a fontset by name." + ) + .def("find_style", find_style, - (arg("style_name")), + (arg("name")), "Query the Map for a style by name and return\n" "a style object if found or raise KeyError\n" "style if not found.\n" @@ -452,6 +484,7 @@ void export_map() "about the hit areas rendered on the map.\n" ) + .def("__deepcopy__",&map_deepcopy) .add_property("extra_attributes",make_function(attr_nonconst,return_value_policy()),"TODO") .add_property("parameters",make_function(params_nonconst,return_value_policy()),"TODO") diff --git a/bindings/python/mapnik_parameters.cpp b/bindings/python/mapnik_parameters.cpp index a202f8190..7572aaf4a 100644 --- a/bindings/python/mapnik_parameters.cpp +++ b/bindings/python/mapnik_parameters.cpp @@ -144,7 +144,7 @@ mapnik::parameter get_params_by_index(mapnik::parameters const& p, int index) parameters::const_iterator end = p.end(); unsigned idx = 0; - while (itr != p.end()) + while (itr != end) { if (idx == index) { diff --git a/bindings/python/mapnik_python.cpp b/bindings/python/mapnik_python.cpp index 768bb6686..52b846a8d 100644 --- a/bindings/python/mapnik_python.cpp +++ b/bindings/python/mapnik_python.cpp @@ -47,6 +47,7 @@ void export_style(); void export_stroke(); void export_feature(); void export_featureset(); +void export_fontset(); void export_datasource(); void export_datasource_cache(); void export_symbolizer(); @@ -397,6 +398,7 @@ BOOST_PYTHON_MODULE(_mapnik) export_geometry(); export_feature(); export_featureset(); + export_fontset(); export_datasource(); export_parameters(); export_color(); diff --git a/bindings/python/mapnik_rule.cpp b/bindings/python/mapnik_rule.cpp index b226dc865..b6f3e4bc8 100644 --- a/bindings/python/mapnik_rule.cpp +++ b/bindings/python/mapnik_rule.cpp @@ -86,7 +86,7 @@ struct rule_pickle_suite : boost::python::pickle_suite static boost::python::tuple getinitargs(const rule& r) { - return boost::python::make_tuple(r.get_name(),r.get_title(),r.get_min_scale(),r.get_max_scale()); + return boost::python::make_tuple(r.get_name(),r.get_min_scale(),r.get_max_scale()); } static boost::python::tuple @@ -102,7 +102,7 @@ struct rule_pickle_suite : boost::python::pickle_suite // We serialize filter expressions AST as strings std::string filter_expr = to_expression_string(*r.get_filter()); - return boost::python::make_tuple(r.get_abstract(),filter_expr,r.has_else_filter(),r.has_also_filter(),syms); + return boost::python::make_tuple(filter_expr,r.has_else_filter(),r.has_also_filter(),syms); } static void @@ -119,11 +119,6 @@ struct rule_pickle_suite : boost::python::pickle_suite } if (state[0]) - { - r.set_title(extract(state[0])); - } - - if (state[1]) { rule dfl; std::string filter = extract(state[1]); @@ -134,12 +129,12 @@ struct rule_pickle_suite : boost::python::pickle_suite } } - if (state[2]) + if (state[1]) { r.set_else(true); } - if (state[3]) + if (state[2]) { r.set_also(true); } @@ -176,18 +171,12 @@ void export_rule() class_("Rule",init<>("default constructor")) .def(init >()) + boost::python::optional >()) .def_pickle(rule_pickle_suite()) .add_property("name",make_function (&rule::get_name, return_value_policy()), &rule::set_name) - .add_property("title",make_function - (&rule::get_title,return_value_policy()), - &rule::set_title) - .add_property("abstract",make_function - (&rule::get_abstract,return_value_policy()), - &rule::set_abstract) .add_property("filter",make_function (&rule::get_filter,return_value_policy()), &rule::set_filter) diff --git a/include/mapnik/attribute_collector.hpp b/include/mapnik/attribute_collector.hpp index b9b62a89c..e256a6c9e 100644 --- a/include/mapnik/attribute_collector.hpp +++ b/include/mapnik/attribute_collector.hpp @@ -213,6 +213,12 @@ struct symbolizer_attributes : public boost::static_visitor<> void operator () (building_symbolizer const& sym) { + expression_ptr const& height_expr = sym.height(); + if (height_expr) + { + expression_attributes f_attr(names_); + boost::apply_visitor(f_attr,*height_expr); + } collect_metawriter(sym); } // TODO - support remaining syms diff --git a/include/mapnik/feature_style_processor.hpp b/include/mapnik/feature_style_processor.hpp index d0e1b3b99..4e20c2e42 100644 --- a/include/mapnik/feature_style_processor.hpp +++ b/include/mapnik/feature_style_processor.hpp @@ -23,8 +23,16 @@ #ifndef MAPNIK_FEATURE_STYLE_PROCESSOR_HPP #define MAPNIK_FEATURE_STYLE_PROCESSOR_HPP +// mapnik +#include +#include +#include + + +// stl #include #include +#include namespace mapnik { @@ -62,11 +70,23 @@ private: /*! * @return render a layer given a projection and scale. */ - void apply_to_layer(layer const& lay, Processor & p, + void apply_to_layer(layer const& lay, + Processor & p, projection const& proj0, double scale_denom, std::set& names); + /*! + * @return renders a featureset with the given styles. + */ + void render_style(layer const& lay, + Processor & p, + feature_type_style* style, + std::string const& style_name, + featureset_ptr features, + proj_transform const& prj_trans, + double scale_denom); + Map const& m_; double scale_factor_; }; diff --git a/include/mapnik/feature_type_style.hpp b/include/mapnik/feature_type_style.hpp index ce47a891f..74e63ae0b 100644 --- a/include/mapnik/feature_type_style.hpp +++ b/include/mapnik/feature_type_style.hpp @@ -1,5 +1,5 @@ /***************************************************************************** - * + * * This file is part of Mapnik (c++ mapping toolkit) * * Copyright (C) 2011 Artem Pavlenko @@ -23,7 +23,7 @@ #ifndef MAPNIK_FEATURE_TYPE_STYLE_HPP #define MAPNIK_FEATURE_TYPE_STYLE_HPP -// mapnik +// mapnik #include #include #include @@ -43,29 +43,43 @@ enum filter_mode_enum { DEFINE_ENUM( filter_mode_e, filter_mode_enum ); typedef std::vector rules; +typedef std::vector rule_ptrs; + class MAPNIK_DECL feature_type_style { private: rules rules_; filter_mode_e filter_mode_; + + // The rule_ptrs vectors are only valid for the scale_denom_validity_. + double scale_denom_validity_; + rule_ptrs if_rules_; + rule_ptrs else_rules_; + rule_ptrs also_rules_; public: feature_type_style(); feature_type_style(feature_type_style const& rhs, bool deep_copy = false); - + feature_type_style& operator=(feature_type_style const& rhs); - + void add_rule(rule const& rule); - + rules const& get_rules() const; + rule_ptrs const& get_if_rules(double scale_denom); + rule_ptrs const& get_else_rules(double scale_denom); + rule_ptrs const& get_also_rules(double scale_denom); rules &get_rules_nonconst(); - + void set_filter_mode(filter_mode_e mode); filter_mode_e get_filter_mode() const; - + ~feature_type_style() {} + +private: + void update_rule_cache(double scale_denom); }; } diff --git a/include/mapnik/font_engine_freetype.hpp b/include/mapnik/font_engine_freetype.hpp index fcdbb9740..e72dc4538 100644 --- a/include/mapnik/font_engine_freetype.hpp +++ b/include/mapnik/font_engine_freetype.hpp @@ -246,7 +246,7 @@ public: static bool register_font(std::string const& file_name); static bool register_fonts(std::string const& dir, bool recurse = false); static std::vector face_names(); - static std::map const& get_mapping(); + static std::map > const& get_mapping(); face_ptr create_face(std::string const& family_name); stroker_ptr create_stroker(); virtual ~freetype_engine(); @@ -256,7 +256,7 @@ private: #ifdef MAPNIK_THREADSAFE static boost::mutex mutex_; #endif - static std::map name2file_; + static std::map > name2file_; }; template diff --git a/include/mapnik/geometry.hpp b/include/mapnik/geometry.hpp index 965bc4ee8..6ae01d179 100644 --- a/include/mapnik/geometry.hpp +++ b/include/mapnik/geometry.hpp @@ -36,29 +36,24 @@ namespace mapnik { enum eGeomType { Point = 1, - LineString, - Polygon, - MultiPoint, - MultiLineString, - MultiPolygon + LineString = 2, + Polygon = 3 }; - template class Container=vertex_vector> -class geometry +class geometry : private::boost::noncopyable { public: typedef T coord_type; typedef Container container_type; typedef typename container_type::value_type value_type; - private: container_type cont_; eGeomType type_; mutable unsigned itr_; public: - geometry(eGeomType type) + explicit geometry(eGeomType type) : type_(type), itr_(0) {} @@ -168,12 +163,12 @@ public: */ void label_position(double *x, double *y) const { - if (type_ == LineString || type_ == MultiLineString) + if (type_ == LineString) { middle_point(x,y); return; } - + unsigned size = cont_.size(); if (size < 3) { @@ -232,7 +227,7 @@ public: /* summarized distance centroid */ void label_position3(double *x, double *y) const { - if (type_ == LineString || type_ == MultiLineString) + if (type_ == LineString) { middle_point(x,y); return; @@ -392,7 +387,7 @@ public: typedef geometry geometry_type; typedef boost::shared_ptr geometry_ptr; -typedef boost::ptr_vector geometry_containter; +typedef boost::ptr_vector geometry_container; } diff --git a/include/mapnik/layer.hpp b/include/mapnik/layer.hpp index 337bc1872..98d3b6fd9 100644 --- a/include/mapnik/layer.hpp +++ b/include/mapnik/layer.hpp @@ -52,32 +52,13 @@ public: * @brief Set the name of the layer. */ void set_name(std::string const& name); - + /*! * @return the name of the layer. */ + const std::string& name() const; - - /*! - * @brief Set the title of the layer. - */ - void set_title(std::string const& title); - - /*! - * @return the title of the layer. - */ - const std::string& title() const; - - /*! - * @brief Set the abstract of the layer. - */ - void set_abstract(std::string const& abstract); - - /*! - * @return the abstract of the layer. - */ - const std::string& abstract() const; - + /*! * @brief Set the SRS of the layer. */ @@ -180,6 +161,16 @@ public: */ bool cache_features() const; + /*! + * @param group_by Set the field rendering of this layer is grouped by. + */ + void set_group_by(std::string column); + + /*! + * @return The field rendering of this layer is grouped by. + */ + std::string group_by() const; + /*! * @brief Attach a datasource for this layer. * @@ -202,16 +193,15 @@ private: void swap(const layer& other); std::string name_; - std::string title_; - std::string abstract_; std::string srs_; - + double minZoom_; double maxZoom_; bool active_; bool queryable_; bool clear_label_cache_; bool cache_features_; + std::string group_by_; std::vector styles_; datasource_ptr ds_; }; diff --git a/include/mapnik/map.hpp b/include/mapnik/map.hpp index bbc5d9432..3e24b540b 100644 --- a/include/mapnik/map.hpp +++ b/include/mapnik/map.hpp @@ -218,7 +218,7 @@ public: * @param name The name of the fontset. * @return The fontset if found. If not found return the default map fontset. */ - font_set const& find_fontset(std::string const& name) const; + boost::optional find_fontset(std::string const& name) const; /*! \brief Get all fontsets * @return Const reference to fontsets diff --git a/include/mapnik/memory_datasource.hpp b/include/mapnik/memory_datasource.hpp index 4a51b46a2..55edc8227 100644 --- a/include/mapnik/memory_datasource.hpp +++ b/include/mapnik/memory_datasource.hpp @@ -45,6 +45,7 @@ public: box2d envelope() const; layer_descriptor get_descriptor() const; size_t size() const; + void clear(); private: std::vector features_; mapnik::layer_descriptor desc_; diff --git a/include/mapnik/polygon_symbolizer.hpp b/include/mapnik/polygon_symbolizer.hpp index 809ceced3..a4791eed3 100644 --- a/include/mapnik/polygon_symbolizer.hpp +++ b/include/mapnik/polygon_symbolizer.hpp @@ -26,6 +26,7 @@ // mapnik #include #include +#include namespace mapnik { @@ -79,11 +80,10 @@ struct MAPNIK_DECL building_symbolizer : public symbolizer_base explicit building_symbolizer() : symbolizer_base(), fill_(color(128,128,128)), - height_(0.0), opacity_(1.0) {} - building_symbolizer(color const& fill,double height) + building_symbolizer(color const& fill, expression_ptr height) : symbolizer_base(), fill_(fill), height_(height), @@ -97,11 +97,11 @@ struct MAPNIK_DECL building_symbolizer : public symbolizer_base { fill_ = fill; } - double height() const + expression_ptr height() const { return height_; } - void set_height(double height) + void set_height(expression_ptr height) { height_=height; } @@ -115,7 +115,7 @@ struct MAPNIK_DECL building_symbolizer : public symbolizer_base } private: color fill_; - double height_; + expression_ptr height_; double opacity_; }; } diff --git a/include/mapnik/rule.hpp b/include/mapnik/rule.hpp index 9664d1173..d3185bef9 100644 --- a/include/mapnik/rule.hpp +++ b/include/mapnik/rule.hpp @@ -39,6 +39,7 @@ #include // boost +#include #include #include #include @@ -125,6 +126,8 @@ typedef boost::variant symbolizer; + + class rule { public: @@ -132,19 +135,113 @@ public: private: std::string name_; - std::string title_; - std::string abstract_; double min_scale_; double max_scale_; symbolizers syms_; expression_ptr filter_; bool else_filter_; bool also_filter_; + + struct deepcopy_symbolizer : public boost::static_visitor<> + { + + void operator () (markers_symbolizer & sym) const + { + copy_path_ptr(sym); + } + + void operator () (point_symbolizer & sym) const + { + copy_path_ptr(sym); + } + + void operator () (polygon_pattern_symbolizer & sym) const + { + copy_path_ptr(sym); + } + + void operator () (line_pattern_symbolizer & sym) const + { + copy_path_ptr(sym); + } + + void operator () (raster_symbolizer & sym) const + { + raster_colorizer_ptr old_colorizer = sym.get_colorizer(); + raster_colorizer_ptr new_colorizer = raster_colorizer_ptr(); + new_colorizer->set_stops(old_colorizer->get_stops()); + new_colorizer->set_default_mode(old_colorizer->get_default_mode()); + new_colorizer->set_default_color(old_colorizer->get_default_color()); + new_colorizer->set_epsilon(old_colorizer->get_epsilon()); + sym.set_colorizer(new_colorizer); + } + + void operator () (text_symbolizer & sym) const + { + copy_text_ptr(sym); + } + + void operator () (shield_symbolizer & sym) const + { + copy_path_ptr(sym); + copy_text_ptr(sym); + } + + void operator () (building_symbolizer & sym) const + { + copy_height_ptr(sym); + } + + + template void operator () (T &sym) const + { + boost::ignore_unused_variable_warning(sym); + } + + private: + template + void copy_path_ptr(T & sym) const + { + std::string path = path_processor_type::to_string(*sym.get_filename()); + sym.set_filename( parse_path(path) ); + } + + template + void copy_text_ptr(T & sym) const + { + std::string name = to_expression_string(*sym.get_name()); + sym.set_name( parse_expression(name) ); + + // FIXME - orientation doesn't appear to be initialized in constructor? + //std::string orientation = to_expression_string(*sym->get_orientation()); + //sym->set_orientation( parse_expression(orientation) ); + + float text_size = sym.get_text_size(); + position displace = sym.get_displacement(); + vertical_alignment_e valign = sym.get_vertical_alignment(); + horizontal_alignment_e halign = sym.get_horizontal_alignment(); + justify_alignment_e jalign = sym.get_justify_alignment(); + + text_placements_ptr placements = text_placements_ptr(boost::make_shared()); + sym.set_placement_options( placements ); + sym.set_text_size(text_size); + sym.set_displacement(displace); + sym.set_vertical_alignment(valign); + sym.set_horizontal_alignment(halign); + sym.set_justify_alignment(jalign); + } + + template + void copy_height_ptr(T & sym) const + { + std::string height_expr = to_expression_string(sym.height()); + sym.set_height(parse_expression(height_expr,"utf8")); + } + }; + public: rule() : name_(), - title_(), - abstract_(), min_scale_(0), max_scale_(std::numeric_limits::infinity()), syms_(), @@ -153,11 +250,9 @@ public: also_filter_(false) {} rule(const std::string& name, - const std::string& title="", double min_scale_denominator=0, double max_scale_denominator=std::numeric_limits::infinity()) : name_(name), - title_(title), min_scale_(min_scale_denominator), max_scale_(max_scale_denominator), syms_(), @@ -167,8 +262,6 @@ public: rule(const rule& rhs, bool deep_copy = false) : name_(rhs.name_), - title_(rhs.title_), - abstract_(rhs.abstract_), min_scale_(rhs.min_scale_), max_scale_(rhs.max_scale_), syms_(rhs.syms_), @@ -177,48 +270,17 @@ public: also_filter_(rhs.also_filter_) { if (deep_copy) { - //std::string expr = to_expression_string(rhs.filter_); - //filter_ = parse_expression(expr,"utf8"); - symbolizers::iterator it = syms_.begin(), - end = syms_.end(); + std::string expr = to_expression_string(*filter_); + filter_ = parse_expression(expr,"utf8"); + symbolizers::const_iterator it = syms_.begin(); + symbolizers::const_iterator end = syms_.end(); // FIXME - metawriter_ptr? - for(; it != end; ++it) { - - /*if (polygon_symbolizer *sym = boost::get(&(*it))) { - // no shared pointers - } else if (line_symbolizer *sym = boost::get(&(*it))) { - // no shared pointers - } else if (building_symbolizer *sym = boost::get(&(*it))) { - // no shared pointers - }*/ - - if (markers_symbolizer *sym = boost::get(&(*it))) { - copy_path_ptr(sym); - } else if (point_symbolizer *sym = boost::get(&(*it))) { - copy_path_ptr(sym); - } else if (polygon_pattern_symbolizer *sym = boost::get(&(*it))) { - copy_path_ptr(sym); - } else if (line_pattern_symbolizer *sym = boost::get(&(*it))) { - copy_path_ptr(sym); - } else if (raster_symbolizer *sym = boost::get(&(*it))) { - raster_colorizer_ptr old_colorizer = sym->get_colorizer(), - new_colorizer = raster_colorizer_ptr(); - - new_colorizer->set_stops( old_colorizer->get_stops()); - new_colorizer->set_default_mode( old_colorizer->get_default_mode() ); - new_colorizer->set_default_color( old_colorizer->get_default_color() ); - new_colorizer->set_epsilon( old_colorizer->get_epsilon() ); - - sym->set_colorizer(new_colorizer); - } else if (shield_symbolizer *sym = boost::get(&(*it))) { - copy_path_ptr(sym); - copy_text_ptr(sym); - } else if (text_symbolizer *sym = boost::get(&(*it))) { - copy_text_ptr(sym); - } + for(; it != end; ++it) + { + boost::apply_visitor(deepcopy_symbolizer(),*it); } } } @@ -263,27 +325,7 @@ public: { return name_; } - - std::string const& get_title() const - { - return title_; - } - - void set_title(std::string const& title) - { - title_=title; - } - - void set_abstract(std::string const& abstract) - { - abstract_=abstract; - } - - std::string const& get_abstract() const - { - return abstract_; - } - + void append(const symbolizer& sym) { syms_.push_back(sym); @@ -362,48 +404,13 @@ private: void swap(rule& rhs) throw() { name_=rhs.name_; - title_=rhs.title_; - abstract_=rhs.abstract_; min_scale_=rhs.min_scale_; max_scale_=rhs.max_scale_; syms_=rhs.syms_; filter_=rhs.filter_; else_filter_=rhs.else_filter_; also_filter_=rhs.also_filter_; - } - - template - void copy_path_ptr(T* sym) - { - std::string path = path_processor_type::to_string(*sym->get_filename()); - sym->set_filename( parse_path(path) ); - } - - template - void copy_text_ptr(T* sym) - { - std::string name = to_expression_string(*sym->get_name()); - sym->set_name( parse_expression(name) ); - - // FIXME - orientation doesn't appear to be initialized in constructor? - //std::string orientation = to_expression_string(*sym->get_orientation()); - //sym->set_orientation( parse_expression(orientation) ); - - float text_size = sym->get_text_size(); - position displace = sym->get_displacement(); - vertical_alignment_e valign = sym->get_vertical_alignment(); - horizontal_alignment_e halign = sym->get_horizontal_alignment(); - justify_alignment_e jalign = sym->get_justify_alignment(); - - text_placements_ptr placements = text_placements_ptr(boost::make_shared()); - sym->set_placement_options( placements ); - - sym->set_text_size(text_size); - sym->set_displacement(displace); - sym->set_vertical_alignment(valign); - sym->set_horizontal_alignment(halign); - sym->set_justify_alignment(jalign); - } + } }; } diff --git a/include/mapnik/util/deepcopy.hpp b/include/mapnik/util/deepcopy.hpp new file mode 100644 index 000000000..c81814518 --- /dev/null +++ b/include/mapnik/util/deepcopy.hpp @@ -0,0 +1,37 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2011 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ + +//$Id$ + +#ifndef MAPNIK_DEEPCOPY_HPP +#define MAPNIK_DEEPCOPY_HPP + +#include + +namespace mapnik { namespace util { + +// poor man deepcopy implementation +void deepcopy(Map const& map_in, Map & map_out); + +}} + +#endif // MAPNIK_DEEPSOPY_HPP diff --git a/include/mapnik/util/geometry_svg_generator.hpp b/include/mapnik/util/geometry_svg_generator.hpp index e69070148..22337ed1c 100644 --- a/include/mapnik/util/geometry_svg_generator.hpp +++ b/include/mapnik/util/geometry_svg_generator.hpp @@ -30,7 +30,6 @@ #include #include #include - // boost #include #include @@ -38,6 +37,8 @@ #include #include #include +#include +#include //#define BOOST_SPIRIT_USE_PHOENIX_V3 1 @@ -46,20 +47,100 @@ namespace mapnik { namespace util { namespace karma = boost::spirit::karma; namespace phoenix = boost::phoenix; -template -bool generate_svg (OutputIterator sink, mapnik::geometry_type const& geom) +namespace detail { +struct get_type { - using boost::spirit::karma::double_; - using boost::spirit::karma::uint_; - using boost::spirit::karma::generate; - return generate (sink, - // begin grammar - ((&uint_(mapnik::SEG_MOVETO) << 'M' | 'L') - << " " << double_ << " " << double_) % ' ' - // end grammar - , geom); + template + struct result { typedef int type; }; + + int operator() (geometry_type const& geom) const + { + return (int)geom.type(); + } +}; + +struct get_first +{ + template + struct result { typedef geometry_type::value_type const type; }; + + geometry_type::value_type const operator() (geometry_type const& geom) const + { + geometry_type::value_type coord; + boost::get<0>(coord) = geom.get_vertex(0,&boost::get<1>(coord),&boost::get<2>(coord)); + return coord; + } +}; + +template +struct coordinate_policy : karma::real_policies +{ + typedef boost::spirit::karma::real_policies base_type; + static int floatfield(T n) { return base_type::fmtflags::fixed; } + static unsigned precision(T n) { return 6u ;} +}; } +template +struct svg_generator : + karma::grammar +{ + + svg_generator() + : svg_generator::base_type(svg) + { + using boost::spirit::karma::uint_; + using boost::spirit::karma::_val; + using boost::spirit::karma::_1; + using boost::spirit::karma::lit; + using boost::spirit::karma::_a; + + svg = point | linestring | polygon + ; + + point = &uint_(mapnik::Point)[_1 = _type(_val)] + << svg_point [_1 = _first(_val)] + ; + + svg_point = &uint_ + << lit("cx=\"") << coord_type + << lit("\" cy=\"") << coord_type + << lit('\"') + ; + + linestring = &uint_(mapnik::LineString)[_1 = _type(_val)] + << svg_path + ; + + polygon = &uint_(mapnik::Polygon)[_1 = _type(_val)] + << svg_path + ; + + svg_path %= ((&uint_(mapnik::SEG_MOVETO) << lit('M') + | &uint_(mapnik::SEG_LINETO) [_a +=1] << karma::string [if_(_a == 1) [_1 = "L" ] ]) + << lit(' ') << coord_type << lit(' ') << coord_type) % lit(' ') + ; + + + + } + // rules + karma::rule svg; + karma::rule point; + karma::rule linestring; + karma::rule polygon; + + karma::rule svg_point; + karma::rule, geometry_type const& ()> svg_path; + + // phoenix functions + phoenix::function _type; + phoenix::function _first; + // + karma::real_generator > coord_type; + +}; + }} #endif // MAPNIK_GEOMETRY_SVG_GENERATOR_HPP diff --git a/include/mapnik/util/geometry_to_wkb.hpp b/include/mapnik/util/geometry_to_wkb.hpp index aa226ce96..6882a8c5c 100644 --- a/include/mapnik/util/geometry_to_wkb.hpp +++ b/include/mapnik/util/geometry_to_wkb.hpp @@ -1,5 +1,5 @@ /***************************************************************************** - * + * * This file is part of Mapnik (c++ mapping toolkit) * * Copyright (C) 2011 Artem Pavlenko @@ -61,11 +61,11 @@ enum wkbByteOrder { }; -inline void reverse_bytes(char size, char *address) +inline void reverse_bytes(char size, char *address) { char * first = address; char * last = first + size - 1; - for(;first < last;++first, --last) + for(;first < last;++first, --last) { char x = *last; *last = *first; @@ -80,7 +80,7 @@ inline void write (S & stream, T val, std::size_t size, wkbByteOrder byte_order) bool need_swap = byte_order ? wkbNDR : wkbXDR; #else bool need_swap = byte_order ? wkbXDR : wkbNDR; -#endif +#endif char* buf = reinterpret_cast(&val); if (need_swap) { @@ -95,22 +95,22 @@ struct wkb_buffer : size_(size), data_( (size_!=0) ? static_cast(::operator new (size_)):0) {} - + ~wkb_buffer() { ::operator delete(data_); } - + inline std::size_t size() const { return size_; } - - inline char* buffer() + + inline char* buffer() { return data_; } - + std::size_t size_; char * data_; }; @@ -120,10 +120,10 @@ typedef boost::shared_ptr wkb_buffer_ptr; wkb_buffer_ptr to_point_wkb( geometry_type const& g, wkbByteOrder byte_order) { assert(g.num_points() == 1); - std::size_t size = 1 + 4 + 8*2 ; // byteOrder + wkbType + Point + std::size_t size = 1 + 4 + 8*2 ; // byteOrder + wkbType + Point wkb_buffer_ptr wkb = boost::make_shared(size); boost::interprocess::bufferstream ss(wkb->buffer(), wkb->size(), std::ios::out | std::ios::binary); - ss.write(reinterpret_cast(&byte_order),1); + ss.write(reinterpret_cast(&byte_order),1); int type = static_cast(mapnik::Point); write(ss,type,4,byte_order); double x,y; @@ -138,10 +138,10 @@ wkb_buffer_ptr to_line_string_wkb( geometry_type const& g, wkbByteOrder byte_ord { unsigned num_points = g.num_points(); assert(num_points > 1); - std::size_t size = 1 + 4 + 4 + 8*2*num_points ; // byteOrder + wkbType + numPoints + Point*numPoints + std::size_t size = 1 + 4 + 4 + 8*2*num_points ; // byteOrder + wkbType + numPoints + Point*numPoints wkb_buffer_ptr wkb = boost::make_shared(size); boost::interprocess::bufferstream ss(wkb->buffer(), wkb->size(), std::ios::out | std::ios::binary); - ss.write(reinterpret_cast(&byte_order),1); + ss.write(reinterpret_cast(&byte_order),1); int type = static_cast(mapnik::LineString); write(ss,type,4,byte_order); write(ss,num_points,4,byte_order); @@ -164,29 +164,29 @@ wkb_buffer_ptr to_polygon_wkb( geometry_type const& g, wkbByteOrder byte_order) typedef std::pair point_type; typedef std::vector linear_ring; boost::ptr_vector rings; - + double x,y; std::size_t size = 1 + 4 + 4 ; // byteOrder + wkbType + numRings for (unsigned i=0; i< num_points; ++i) { unsigned command = g.get_vertex(i,&x,&y); - if (command == SEG_MOVETO) - { + if (command == SEG_MOVETO) + { rings.push_back(new linear_ring); // start new loop size += 4; // num_points } rings.back().push_back(std::make_pair(x,y)); - size += 2 * 8; // point + size += 2 * 8; // point } unsigned num_rings = rings.size(); wkb_buffer_ptr wkb = boost::make_shared(size); boost::interprocess::bufferstream ss(wkb->buffer(), wkb->size(), std::ios::out | std::ios::binary); - ss.write(reinterpret_cast(&byte_order),1); + ss.write(reinterpret_cast(&byte_order),1); int type = static_cast(mapnik::Polygon); write(ss,type,4,byte_order); write(ss,num_rings,4,byte_order); - + BOOST_FOREACH ( linear_ring const& ring, rings) { unsigned num_points = ring.size(); @@ -199,7 +199,7 @@ wkb_buffer_ptr to_polygon_wkb( geometry_type const& g, wkbByteOrder byte_order) write(ss,y,8,byte_order); } } - + assert(ss.good()); return wkb; } @@ -207,7 +207,7 @@ wkb_buffer_ptr to_polygon_wkb( geometry_type const& g, wkbByteOrder byte_order) wkb_buffer_ptr to_wkb(geometry_type const& g, wkbByteOrder byte_order ) { wkb_buffer_ptr wkb; - + switch (g.type()) { case mapnik::Point : @@ -219,16 +219,57 @@ wkb_buffer_ptr to_wkb(geometry_type const& g, wkbByteOrder byte_order ) case mapnik::Polygon: wkb = to_polygon_wkb(g, byte_order); break; - case mapnik::MultiPoint: - case mapnik::MultiLineString: - case mapnik::MultiPolygon: - break; default: break; } return wkb; } +wkb_buffer_ptr to_wkb(geometry_container const& paths, wkbByteOrder byte_order ) +{ + if (paths.size() == 1) + { + // single geometry + return to_wkb(paths.front(), byte_order); + } + + if (paths.size() > 1) + { + // multi geometry or geometry collection + std::vector wkb_cont; + bool collection = false; + int multi_type = 0; + size_t multi_size = 1 + 4 + 4; + geometry_container::const_iterator itr = paths.begin(); + geometry_container::const_iterator end = paths.end(); + for ( ; itr!=end; ++itr) + { + wkb_buffer_ptr wkb = to_wkb(*itr,byte_order); + multi_size += wkb->size(); + int type = static_cast(itr->type()); + if (multi_type > 0 && multi_type != itr->type()) + collection = true; + multi_type = type; + wkb_cont.push_back(wkb); + } + + wkb_buffer_ptr multi_wkb = boost::make_shared(multi_size); + boost::interprocess::bufferstream ss(multi_wkb->buffer(), multi_wkb->size(), std::ios::out | std::ios::binary); + ss.write(reinterpret_cast(&byte_order),1); + multi_type = collection ? 7 : multi_type + 3; + write(ss,multi_type, 4, byte_order); + write(ss,paths.size(),4,byte_order); + + BOOST_FOREACH ( wkb_buffer_ptr const& wkb, wkb_cont) + { + ss.write(wkb->buffer(),wkb->size()); + } + return multi_wkb; + } + + return wkb_buffer_ptr(); +} + }} diff --git a/include/mapnik/util/geometry_to_wkt.hpp b/include/mapnik/util/geometry_to_wkt.hpp index 962909f00..42735c3a2 100644 --- a/include/mapnik/util/geometry_to_wkt.hpp +++ b/include/mapnik/util/geometry_to_wkt.hpp @@ -42,7 +42,16 @@ bool to_wkt(std::string & wkt, mapnik::geometry_type const& geom) { typedef std::back_insert_iterator sink_type; sink_type sink(wkt); - wkt_generator generator; + wkt_generator generator(true); + bool result = karma::generate(sink, generator, geom); + return result; +} + +bool to_wkt(std::string & wkt, mapnik::geometry_container const& geom) +{ + typedef std::back_insert_iterator sink_type; + sink_type sink(wkt); + wkt_multi_generator generator; bool result = karma::generate(sink, generator, geom); return result; } diff --git a/include/mapnik/util/geometry_wkt_generator.hpp b/include/mapnik/util/geometry_wkt_generator.hpp index 38ce28a02..bd3b71a65 100644 --- a/include/mapnik/util/geometry_wkt_generator.hpp +++ b/include/mapnik/util/geometry_wkt_generator.hpp @@ -30,7 +30,6 @@ #include #include #include - // boost #include #include @@ -44,11 +43,24 @@ //#define BOOST_SPIRIT_USE_PHOENIX_V3 1 +namespace boost { namespace spirit { namespace traits { + +// make gcc and darwin toolsets happy. +template <> +struct is_container + : mpl::false_ +{}; + +}}} + + namespace mapnik { namespace util { namespace karma = boost::spirit::karma; namespace phoenix = boost::phoenix; +namespace { + struct get_type { template @@ -56,7 +68,7 @@ struct get_type int operator() (geometry_type const& geom) const { - return (int)geom.type(); + return static_cast(geom.type()); } }; @@ -73,20 +85,61 @@ struct get_first } }; + +struct multi_geometry_ +{ + template + struct result { typedef bool type; }; + + bool operator() (geometry_container const& geom) const + { + return geom.size() > 1 ? true : false; + } +}; + +struct multi_geometry_type +{ + template + struct result { typedef boost::tuple type; }; + + boost::tuple operator() (geometry_container const& geom) const + { + unsigned type = 0u; + bool collection = false; + + geometry_container::const_iterator itr = geom.begin(); + geometry_container::const_iterator end = geom.end(); + + for ( ; itr != end; ++itr) + { + if (type != 0 && itr->type() != type) + { + collection = true; + break; + } + type = itr->type(); + } + return boost::tuple(type, collection); + } +}; + + template -struct coordinate_policy : karma::real_policies +struct wkt_coordinate_policy : karma::real_policies { typedef boost::spirit::karma::real_policies base_type; static int floatfield(T n) { return base_type::fmtflags::fixed; } + static unsigned precision(T n) { return 6 ;} }; +} template struct wkt_generator : karma::grammar { - wkt_generator() + wkt_generator(bool single = false) : wkt_generator::base_type(wkt) { using boost::spirit::karma::uint_; @@ -96,22 +149,27 @@ struct wkt_generator : using boost::spirit::karma::_a; using boost::spirit::karma::_r1; using boost::spirit::karma::eps; + using boost::spirit::karma::string; wkt = point | linestring | polygon ; point = &uint_(mapnik::Point)[_1 = _type(_val)] - << lit("Point(") << point_coord [_1 = _first(_val)] << lit(')') + << string[ phoenix::if_ (single) [_1 = "Point("] + .else_[_1 = "("]] + << point_coord [_1 = _first(_val)] << lit(')') ; linestring = &uint_(mapnik::LineString)[_1 = _type(_val)] - << lit("LineString(") + << string[ phoenix::if_ (single) [_1 = "LineString("] + .else_[_1 = "("]] << coords << lit(')') ; polygon = &uint_(mapnik::Polygon)[_1 = _type(_val)] - << lit("Polygon(") + << string[ phoenix::if_ (single) [_1 = "Polygon("] + .else_[_1 = "("]] << coords2 << lit("))") ; @@ -120,8 +178,8 @@ struct wkt_generator : ; polygon_coord %= ( &uint_(mapnik::SEG_MOVETO) << eps[_r1 += 1] - << karma::string[ if_ (_r1 > 1) [_1 = "),("] - .else_[_1 = "("] ] | &uint_ << ",") + << string[ if_ (_r1 > 1) [_1 = "),("] + .else_[_1 = "("] ] | &uint_ << ",") << coord_type << lit(' ') << coord_type @@ -143,16 +201,69 @@ struct wkt_generator : karma::rule coords; karma::rule, geometry_type const& ()> coords2; karma::rule point_coord; - karma::rule polygon_coord; + karma::rule polygon_coord; // phoenix functions phoenix::function _type; phoenix::function _first; // - karma::real_generator > coord_type; + karma::real_generator > coord_type; }; + + +template +struct wkt_multi_generator : + karma::grammar >, geometry_container const& ()> +{ + + wkt_multi_generator() + : wkt_multi_generator::base_type(wkt) + { + using boost::spirit::karma::lit; + using boost::spirit::karma::eps; + using boost::spirit::karma::_val; + using boost::spirit::karma::_1; + using boost::spirit::karma::_a; + + geometry_types.add + (mapnik::Point,"Point") + (mapnik::LineString,"LineString") + (mapnik::Polygon,"Polygon") + ; + + wkt = eps(phoenix::at_c<1>(_a))[_a = _multi_type(_val)] + << lit("GeometryCollection(") << geometry << lit(")") + | eps(is_multi(_val)) << lit("Multi") << geometry_types[_1 = phoenix::at_c<0>(_a)] + << "(" << multi_geometry << ")" + | geometry + ; + + geometry = -(single_geometry % lit(',')) + ; + + single_geometry = geometry_types[_1 = _type(_val)] << path + ; + + multi_geometry = -(path % lit(',')) + ; + + } + // rules + karma::rule >, geometry_container const& ()> wkt; + karma::rule geometry; + karma::rule single_geometry; + karma::rule multi_geometry; + wkt_generator path; + // phoenix + phoenix::function is_multi; + phoenix::function _multi_type; + phoenix::function _type; + // + karma::symbols geometry_types; +}; + }} diff --git a/include/mapnik/wkb.hpp b/include/mapnik/wkb.hpp index 77c7c04c6..55df4d102 100644 --- a/include/mapnik/wkb.hpp +++ b/include/mapnik/wkb.hpp @@ -27,6 +27,8 @@ #include #include #include +// boost +#include namespace mapnik { @@ -49,19 +51,14 @@ enum wkbFormat wkbSpatiaLite=3 }; -class MAPNIK_DECL geometry_utils +class MAPNIK_DECL geometry_utils : private boost::noncopyable { public: static void from_wkb (boost::ptr_vector& paths, const char* wkb, unsigned size, - bool multiple_geometries = false, wkbFormat format = wkbGeneric); -private: - geometry_utils(); - geometry_utils(geometry_utils const&); - geometry_utils& operator=(const geometry_utils&); }; } diff --git a/plugins/input/csv/csv_datasource.cpp b/plugins/input/csv/csv_datasource.cpp index 6280d16f4..1d44b90c2 100644 --- a/plugins/input/csv/csv_datasource.cpp +++ b/plugins/input/csv/csv_datasource.cpp @@ -489,10 +489,12 @@ void csv_datasource::parse_csv(T& stream, std::string::const_iterator str_beg = value.begin(); std::string::const_iterator str_end = value.end(); bool r = qi::phrase_parse(str_beg,str_end, - ( - qi::lit("POINT") >> '(' >> double_[ref(x) = _1] >> double_[ref(y) = _1] >> ')' - ), - ascii::space); + ( + qi::lit("POINT") >> '(' + >> double_[ref(x) = _1] + >> double_[ref(y) = _1] >> ')' + ), + ascii::space); if (r && (str_beg == str_end)) { @@ -615,28 +617,27 @@ void csv_datasource::parse_csv(T& stream, } } - // add all values as attributes - // here we detect numbers and treat everything else as pure strings - // this is intentional since boolean and null types are not common in csv editors - if (value.empty()) - { - UnicodeString ustr = tr.transcode(value.c_str()); - boost::put(*feature,fld_name,ustr); - if (feature_count == 1) - { - desc_.add_descriptor(mapnik::attribute_descriptor(fld_name,mapnik::String)); - } - } - // only true strings are this long - else if (value_length > 20) - { - UnicodeString ustr = tr.transcode(value.c_str()); - boost::put(*feature,fld_name,ustr); - if (feature_count == 1) - { - desc_.add_descriptor(mapnik::attribute_descriptor(fld_name,mapnik::String)); - } + // now, add all values as attributes + /* First we detect likely strings, then try parsing likely numbers, + finally falling back to string type + * We intentionally do not try to detect boolean or null types + since they are not common in csv + * Likely strings are either empty values, very long values + or value with leading zeros like 001 (which are not safe + to assume are numbers) + */ + bool has_dot = value.find(".") != std::string::npos; + if (value.empty() || + (value_length > 20) || + (value_length > 1 && !has_dot && value[0] == '0')) + { + UnicodeString ustr = tr.transcode(value.c_str()); + boost::put(*feature,fld_name,ustr); + if (feature_count == 1) + { + desc_.add_descriptor(mapnik::attribute_descriptor(fld_name,mapnik::String)); + } } else if ((value[0] >= '0' && value[0] <= '9') || value[0] == '-') { @@ -646,12 +647,14 @@ void csv_datasource::parse_csv(T& stream, bool r = qi::phrase_parse(str_beg,str_end,qi::double_,ascii::space,float_val); if (r && (str_beg == str_end)) { - if (value.find(".") != std::string::npos) + if (has_dot) { boost::put(*feature,fld_name,float_val); if (feature_count == 1) { - desc_.add_descriptor(mapnik::attribute_descriptor(fld_name,mapnik::Double)); + desc_.add_descriptor( + mapnik::attribute_descriptor( + fld_name,mapnik::Double)); } } else @@ -660,7 +663,9 @@ void csv_datasource::parse_csv(T& stream, boost::put(*feature,fld_name,val); if (feature_count == 1) { - desc_.add_descriptor(mapnik::attribute_descriptor(fld_name,mapnik::Integer)); + desc_.add_descriptor( + mapnik::attribute_descriptor( + fld_name,mapnik::Integer)); } } } @@ -671,7 +676,9 @@ void csv_datasource::parse_csv(T& stream, boost::put(*feature,fld_name,ustr); if (feature_count == 1) { - desc_.add_descriptor(mapnik::attribute_descriptor(fld_name,mapnik::String)); + desc_.add_descriptor( + mapnik::attribute_descriptor( + fld_name,mapnik::String)); } } } @@ -682,7 +689,9 @@ void csv_datasource::parse_csv(T& stream, boost::put(*feature,fld_name,ustr); if (feature_count == 1) { - desc_.add_descriptor(mapnik::attribute_descriptor(fld_name,mapnik::String)); + desc_.add_descriptor( + mapnik::attribute_descriptor( + fld_name,mapnik::String)); } } } diff --git a/plugins/input/gdal/gdal_datasource.cpp b/plugins/input/gdal/gdal_datasource.cpp index 1e82e486d..b28d53bf7 100644 --- a/plugins/input/gdal/gdal_datasource.cpp +++ b/plugins/input/gdal/gdal_datasource.cpp @@ -152,10 +152,15 @@ void gdal_datasource::bind() const << tr[4] << "," << tr[5] << std::endl; #endif + // TODO - We should throw for true non-north up images, but the check + // below is clearly too restrictive. + // https://github.com/mapnik/mapnik/issues/970 + /* if (tr[2] != 0 || tr[4] != 0) { throw datasource_exception("GDAL Plugin: only 'north up' images are supported"); } + */ dx_ = tr[1]; dy_ = tr[5]; diff --git a/plugins/input/geos/geos_datasource.cpp b/plugins/input/geos/geos_datasource.cpp index cfa4e1cf4..f09670a46 100644 --- a/plugins/input/geos/geos_datasource.cpp +++ b/plugins/input/geos/geos_datasource.cpp @@ -97,9 +97,7 @@ geos_datasource::geos_datasource(parameters const& params, bool bind) boost::optional geometry = params.get("wkt"); if (! geometry) throw datasource_exception("missing parameter"); geometry_string_ = *geometry; - - multiple_geometries_ = *params_.get("multiple_geometries",false); - + boost::optional ext = params_.get("extent"); if (ext) extent_initialized_ = extent_.from_string(*ext); @@ -270,8 +268,7 @@ featureset_ptr geos_datasource::features(query const& q) const geometry_id_, geometry_data_, geometry_data_name_, - desc_.get_encoding(), - multiple_geometries_); + desc_.get_encoding()); } featureset_ptr geos_datasource::features_at_point(coord2d const& pt) const @@ -290,6 +287,5 @@ featureset_ptr geos_datasource::features_at_point(coord2d const& pt) const geometry_id_, geometry_data_, geometry_data_name_, - desc_.get_encoding(), - multiple_geometries_); + desc_.get_encoding()); } diff --git a/plugins/input/geos/geos_datasource.hpp b/plugins/input/geos/geos_datasource.hpp index 3d2385776..79e846c41 100644 --- a/plugins/input/geos/geos_datasource.hpp +++ b/plugins/input/geos/geos_datasource.hpp @@ -56,7 +56,6 @@ private: mutable std::string geometry_data_name_; mutable int geometry_id_; std::string geometry_string_; - bool multiple_geometries_; }; #endif // GEOS_DATASOURCE_HPP diff --git a/plugins/input/geos/geos_featureset.cpp b/plugins/input/geos/geos_featureset.cpp index bbcbb832d..afd2d71af 100644 --- a/plugins/input/geos/geos_featureset.cpp +++ b/plugins/input/geos/geos_featureset.cpp @@ -53,15 +53,13 @@ geos_featureset::geos_featureset(GEOSGeometry* geometry, int identifier, const std::string& field, const std::string& field_name, - const std::string& encoding, - bool multiple_geometries) + const std::string& encoding) : geometry_(geometry), tr_(new transcoder(encoding)), extent_(extent), identifier_(identifier), field_(field), field_name_(field_name), - multiple_geometries_(multiple_geometries), already_rendered_(false) { } @@ -120,14 +118,12 @@ feature_ptr geos_featureset::next() geometry_utils::from_wkb(feature->paths(), wkb.data(), - wkb.size(), - multiple_geometries_); - + wkb.size()); if (field_ != "") { boost::put(*feature, field_name_, tr_->transcode(field_.c_str())); } - + return feature; } } diff --git a/plugins/input/geos/geos_featureset.hpp b/plugins/input/geos/geos_featureset.hpp index 2b777efaa..713f9ff4c 100644 --- a/plugins/input/geos/geos_featureset.hpp +++ b/plugins/input/geos/geos_featureset.hpp @@ -44,8 +44,7 @@ public: int identifier, const std::string& field, const std::string& field_name, - const std::string& encoding, - bool multiple_geometries); + const std::string& encoding); virtual ~geos_featureset(); mapnik::feature_ptr next(); @@ -56,7 +55,6 @@ private: int identifier_; std::string field_; std::string field_name_; - bool multiple_geometries_; bool already_rendered_; geos_featureset(const geos_featureset&); diff --git a/plugins/input/kismet/kismet_featureset.hpp b/plugins/input/kismet/kismet_featureset.hpp index 424d39fd0..363f3425a 100644 --- a/plugins/input/kismet/kismet_featureset.hpp +++ b/plugins/input/kismet/kismet_featureset.hpp @@ -50,7 +50,6 @@ private: const std::list& knd_list_; boost::scoped_ptr tr_; mapnik::wkbFormat format_; - bool multiple_geometries_; int feature_id_; std::list::const_iterator knd_list_it; mapnik::projection source_; diff --git a/plugins/input/occi/occi_datasource.cpp b/plugins/input/occi/occi_datasource.cpp index f1fd158ca..335146174 100644 --- a/plugins/input/occi/occi_datasource.cpp +++ b/plugins/input/occi/occi_datasource.cpp @@ -94,7 +94,6 @@ occi_datasource::occi_datasource(parameters const& params, bool bind) table_ = *table; } - multiple_geometries_ = *params_.get("multiple_geometries",false); use_spatial_index_ = *params_.get("use_spatial_index",true); use_connection_pool_ = *params_.get("use_connection_pool",true); @@ -559,8 +558,7 @@ featureset_ptr occi_datasource::features(query const& q) const return boost::make_shared(pool_, conn_, s.str(), - desc_.get_encoding(), - multiple_geometries_, + desc_.get_encoding(), use_connection_pool_, row_prefetch_, props.size()); @@ -642,7 +640,6 @@ featureset_ptr occi_datasource::features_at_point(coord2d const& pt) const conn_, s.str(), desc_.get_encoding(), - multiple_geometries_, use_connection_pool_, row_prefetch_, size); diff --git a/plugins/input/occi/occi_datasource.hpp b/plugins/input/occi/occi_datasource.hpp index 4e751eb60..72096ae9e 100644 --- a/plugins/input/occi/occi_datasource.hpp +++ b/plugins/input/occi/occi_datasource.hpp @@ -64,7 +64,6 @@ private: mutable oracle::occi::StatelessConnectionPool* pool_; mutable oracle::occi::Connection* conn_; bool use_connection_pool_; - bool multiple_geometries_; bool use_spatial_index_; static const std::string METADATA_TABLE; }; diff --git a/plugins/input/occi/occi_featureset.cpp b/plugins/input/occi/occi_featureset.cpp index 76e092bc2..b4ea397ad 100644 --- a/plugins/input/occi/occi_featureset.cpp +++ b/plugins/input/occi/occi_featureset.cpp @@ -59,12 +59,10 @@ occi_featureset::occi_featureset(StatelessConnectionPool* pool, Connection* conn, std::string const& sqlstring, std::string const& encoding, - bool multiple_geometries, bool use_connection_pool, unsigned prefetch_rows, unsigned num_attrs) : tr_(new transcoder(encoding)), - multiple_geometries_(multiple_geometries), num_attrs_(num_attrs), feature_id_(1) { @@ -101,7 +99,7 @@ feature_ptr occi_featureset::next() boost::scoped_ptr geom(dynamic_cast(rs_->getObject(1))); if (geom.get()) { - convert_geometry(geom.get(), feature, multiple_geometries_); + convert_geometry(geom.get(), feature); } std::vector listOfColumns = rs_->getColumnListMetaData(); @@ -204,7 +202,7 @@ feature_ptr occi_featureset::next() } -void occi_featureset::convert_geometry(SDOGeometry* geom, feature_ptr feature, bool multiple_geometries) +void occi_featureset::convert_geometry(SDOGeometry* geom, feature_ptr feature) { int gtype = (int)geom->getSdo_gtype(); int dimensions = gtype / 1000; @@ -248,16 +246,13 @@ void occi_featureset::convert_geometry(SDOGeometry* geom, feature_ptr feature, b { const bool is_single_geom = true; const bool is_point_type = false; - const bool multiple_geoms = false; - convert_ordinates(feature, mapnik::LineString, elem_info, ordinates, dimensions, is_single_geom, - is_point_type, - multiple_geoms); + is_point_type); } } break; @@ -267,16 +262,13 @@ void occi_featureset::convert_geometry(SDOGeometry* geom, feature_ptr feature, b { const bool is_single_geom = true; const bool is_point_type = false; - const bool multiple_geoms = false; - convert_ordinates(feature, mapnik::Polygon, elem_info, ordinates, dimensions, is_single_geom, - is_point_type, - multiple_geoms); + is_point_type); } } break; @@ -286,19 +278,15 @@ void occi_featureset::convert_geometry(SDOGeometry* geom, feature_ptr feature, b { const bool is_single_geom = false; const bool is_point_type = true; - const bool multiple_geoms = true; - - // Todo - force using true as multiple_geometries until we have proper multipoint handling - // http://trac.mapnik.org/ticket/458 + // FIXME :http://trac.mapnik.org/ticket/458 convert_ordinates(feature, mapnik::Point, elem_info, ordinates, dimensions, is_single_geom, - is_point_type, - multiple_geoms); + is_point_type); } } break; @@ -315,8 +303,7 @@ void occi_featureset::convert_geometry(SDOGeometry* geom, feature_ptr feature, b ordinates, dimensions, is_single_geom, - is_point_type, - multiple_geometries); + is_point_type); } } break; @@ -333,8 +320,7 @@ void occi_featureset::convert_geometry(SDOGeometry* geom, feature_ptr feature, b ordinates, dimensions, is_single_geom, - is_point_type, - multiple_geometries); + is_point_type); } } @@ -352,8 +338,7 @@ void occi_featureset::convert_geometry(SDOGeometry* geom, feature_ptr feature, b ordinates, dimensions, is_single_geom, - is_point_type, - multiple_geometries); + is_point_type); } } break; @@ -374,8 +359,7 @@ void occi_featureset::convert_ordinates(mapnik::feature_ptr feature, const std::vector& ordinates, const int dimensions, const bool is_single_geom, - const bool is_point_geom, - const bool multiple_geometries) + const bool is_point_geom) { const int elem_size = elem_info.size(); const int ord_size = ordinates.size(); @@ -388,7 +372,7 @@ void occi_featureset::convert_ordinates(mapnik::feature_ptr feature, if (! is_single_geom && elem_size > SDO_ELEM_INFO_SIZE) { - geometry_type* geom = multiple_geometries ? 0 : new geometry_type(geom_type); + geometry_type* geom = new geometry_type(geom_type); if (geom) geom->set_capacity(ord_size); for (int i = SDO_ELEM_INFO_SIZE; i < elem_size; i+=3) @@ -444,16 +428,13 @@ void occi_featureset::convert_ordinates(mapnik::feature_ptr feature, if (is_linear_element) { - if (multiple_geometries) + if (geom) { - if (geom) - { - feature->add_geometry(geom); - } - - geom = new geometry_type(gtype); - geom->set_capacity((next_offset - 1) - (offset - 1 - dimensions)); + feature->add_geometry(geom); } + + geom = new geometry_type(gtype); + geom->set_capacity((next_offset - 1) - (offset - 1 - dimensions)); fill_geometry_type(geom, offset - 1, diff --git a/plugins/input/occi/occi_featureset.hpp b/plugins/input/occi/occi_featureset.hpp index 88977d678..4c2a0db67 100644 --- a/plugins/input/occi/occi_featureset.hpp +++ b/plugins/input/occi/occi_featureset.hpp @@ -42,7 +42,6 @@ public: oracle::occi::Connection* conn, std::string const& sqlstring, std::string const& encoding, - bool multiple_geometries, bool use_connection_pool, unsigned prefetch_rows, unsigned num_attrs); @@ -50,15 +49,14 @@ public: mapnik::feature_ptr next(); private: - void convert_geometry (SDOGeometry* geom, mapnik::feature_ptr feature, bool multiple_geometries); + void convert_geometry (SDOGeometry* geom, mapnik::feature_ptr feature); void convert_ordinates (mapnik::feature_ptr feature, const mapnik::eGeomType& geom_type, const std::vector& elem_info, const std::vector& ordinates, const int dimensions, const bool is_single_geom, - const bool is_point_geom, - const bool multiple_geometries); + const bool is_point_geom); void fill_geometry_type (mapnik::geometry_type* geom, const int real_offset, const int next_offset, @@ -70,7 +68,6 @@ private: oracle::occi::ResultSet* rs_; boost::scoped_ptr tr_; const char* fidcolumn_; - bool multiple_geometries_; unsigned num_attrs_; mutable int feature_id_; }; diff --git a/plugins/input/ogr/ogr_converter.cpp b/plugins/input/ogr/ogr_converter.cpp index 4188e1fab..59f1b2095 100644 --- a/plugins/input/ogr/ogr_converter.cpp +++ b/plugins/input/ogr/ogr_converter.cpp @@ -36,57 +36,34 @@ using mapnik::feature_ptr; using mapnik::geometry_utils; using mapnik::geometry_type; -void ogr_converter::convert_geometry(OGRGeometry* geom, feature_ptr feature, bool multiple_geometries) +void ogr_converter::convert_geometry(OGRGeometry* geom, feature_ptr feature) { + // NOTE: wkbFlatten macro in ogr flattens 2.5d types into base 2d type switch (wkbFlatten(geom->getGeometryType())) { case wkbPoint: convert_point(static_cast(geom), feature); break; + case wkbMultiPoint: + convert_multipoint(static_cast(geom), feature); + break; + case wkbLinearRing: + convert_linestring(static_cast(geom), feature); + break; case wkbLineString: convert_linestring(static_cast(geom), feature); break; + case wkbMultiLineString: + convert_multilinestring(static_cast(geom), feature); + break; case wkbPolygon: convert_polygon(static_cast(geom), feature); break; - case wkbMultiPoint: - if (multiple_geometries) - { - convert_multipoint_2(static_cast(geom), feature); - } - else - { - // Todo - using convert_multipoint_2 until we have proper multipoint handling in convert_multipoint - // http://trac.mapnik.org/ticket/458 - //convert_multipoint(static_cast(geom), feature); - convert_multipoint_2(static_cast(geom), feature); - } - break; - case wkbMultiLineString: - if (multiple_geometries) - { - convert_multilinestring_2(static_cast(geom), feature); - } - else - { - convert_multilinestring(static_cast(geom), feature); - } - break; case wkbMultiPolygon: - if (multiple_geometries) - { - convert_multipolygon_2(static_cast(geom), feature); - } - else - { - convert_multipolygon(static_cast(geom), feature); - } + convert_multipolygon(static_cast(geom), feature); break; case wkbGeometryCollection: - convert_collection(static_cast(geom), feature, multiple_geometries); - break; - case wkbLinearRing: - convert_linestring(static_cast(geom), feature); + convert_collection(static_cast(geom), feature); break; case wkbNone: case wkbUnknown: @@ -151,22 +128,6 @@ void ogr_converter::convert_polygon(OGRPolygon* geom, feature_ptr feature) } void ogr_converter::convert_multipoint(OGRMultiPoint* geom, feature_ptr feature) -{ - int num_geometries = geom->getNumGeometries(); - geometry_type* point = new geometry_type(mapnik::Point); - - for (int i = 0; i < num_geometries; i++) - { - OGRPoint* ogrpoint = static_cast(geom->getGeometryRef(i)); - point->move_to(ogrpoint->getX(), ogrpoint->getY()); - //Todo - need to accept multiple points per mapnik::Point - } - - // Todo - this only gets last point - feature->add_geometry(point); -} - -void ogr_converter::convert_multipoint_2(OGRMultiPoint* geom, feature_ptr feature) { int num_geometries = geom->getNumGeometries(); for (int i = 0; i < num_geometries; i++) @@ -176,34 +137,6 @@ void ogr_converter::convert_multipoint_2(OGRMultiPoint* geom, feature_ptr featur } void ogr_converter::convert_multilinestring(OGRMultiLineString* geom, feature_ptr feature) -{ - int num_geometries = geom->getNumGeometries(); - - int num_points = 0; - for (int i = 0; i < num_geometries; i++) - { - OGRLineString* ls = static_cast(geom->getGeometryRef(i)); - num_points += ls->getNumPoints(); - } - - geometry_type* line = new geometry_type(mapnik::LineString); - line->set_capacity(num_points); - - for (int i = 0; i < num_geometries; i++) - { - OGRLineString* ls = static_cast(geom->getGeometryRef(i)); - num_points = ls->getNumPoints(); - line->move_to(ls->getX(0), ls->getY(0)); - for (int i = 1; i < num_points; ++i) - { - line->line_to(ls->getX(i), ls->getY(i)); - } - } - - feature->add_geometry(line); -} - -void ogr_converter::convert_multilinestring_2(OGRMultiLineString* geom, feature_ptr feature) { int num_geometries = geom->getNumGeometries(); for (int i = 0; i < num_geometries; i++) @@ -213,52 +146,6 @@ void ogr_converter::convert_multilinestring_2(OGRMultiLineString* geom, feature_ } void ogr_converter::convert_multipolygon(OGRMultiPolygon* geom, feature_ptr feature) -{ - int num_geometries = geom->getNumGeometries(); - - int capacity = 0; - for (int i = 0; i < num_geometries; i++) - { - OGRPolygon* p = static_cast(geom->getGeometryRef(i)); - OGRLinearRing* exterior = p->getExteriorRing(); - capacity += exterior->getNumPoints(); - for (int r = 0; r < p->getNumInteriorRings(); r++) - { - OGRLinearRing* interior = p->getInteriorRing(r); - capacity += interior->getNumPoints(); - } - } - - geometry_type* poly = new geometry_type(mapnik::Polygon); - poly->set_capacity(capacity); - - for (int i = 0; i < num_geometries; i++) - { - OGRPolygon* p = static_cast(geom->getGeometryRef(i)); - OGRLinearRing* exterior = p->getExteriorRing(); - int num_points = exterior->getNumPoints(); - int num_interior = p->getNumInteriorRings(); - poly->move_to(exterior->getX(0), exterior->getY(0)); - for (int i = 1; i < num_points; ++i) - { - poly->line_to(exterior->getX(i), exterior->getY(i)); - } - for (int r = 0; r < num_interior; r++) - { - OGRLinearRing* interior = p->getInteriorRing(r); - num_points = interior->getNumPoints(); - poly->move_to(interior->getX(0), interior->getY(0)); - for (int i = 1; i < num_points; ++i) - { - poly->line_to(interior->getX(i), interior->getY(i)); - } - } - } - - feature->add_geometry(poly); -} - -void ogr_converter::convert_multipolygon_2(OGRMultiPolygon* geom, feature_ptr feature) { int num_geometries = geom->getNumGeometries(); for (int i = 0; i < num_geometries; i++) @@ -267,7 +154,7 @@ void ogr_converter::convert_multipolygon_2(OGRMultiPolygon* geom, feature_ptr fe } } -void ogr_converter::convert_collection(OGRGeometryCollection* geom, feature_ptr feature, bool multiple_geometries) +void ogr_converter::convert_collection(OGRGeometryCollection* geom, feature_ptr feature) { int num_geometries = geom->getNumGeometries(); for (int i = 0; i < num_geometries; i++) @@ -275,7 +162,7 @@ void ogr_converter::convert_collection(OGRGeometryCollection* geom, feature_ptr OGRGeometry* g = geom->getGeometryRef(i); if (g != NULL) { - convert_geometry(g, feature, multiple_geometries); + convert_geometry(g, feature); } } } diff --git a/plugins/input/ogr/ogr_converter.hpp b/plugins/input/ogr/ogr_converter.hpp index 0871fce6d..94b198d54 100644 --- a/plugins/input/ogr/ogr_converter.hpp +++ b/plugins/input/ogr/ogr_converter.hpp @@ -33,17 +33,14 @@ class ogr_converter { public: - static void convert_geometry (OGRGeometry* geom, mapnik::feature_ptr feature, bool multiple_geometries); - static void convert_collection (OGRGeometryCollection* geom, mapnik::feature_ptr feature, bool multiple_geometries); + static void convert_geometry (OGRGeometry* geom, mapnik::feature_ptr feature); + static void convert_collection (OGRGeometryCollection* geom, mapnik::feature_ptr feature); static void convert_point (OGRPoint* geom, mapnik::feature_ptr feature); static void convert_linestring (OGRLineString* geom, mapnik::feature_ptr feature); static void convert_polygon (OGRPolygon* geom, mapnik::feature_ptr feature); static void convert_multipoint (OGRMultiPoint* geom, mapnik::feature_ptr feature); - static void convert_multipoint_2 (OGRMultiPoint* geom, mapnik::feature_ptr feature); static void convert_multilinestring (OGRMultiLineString* geom, mapnik::feature_ptr feature); - static void convert_multilinestring_2 (OGRMultiLineString* geom, mapnik::feature_ptr feature); static void convert_multipolygon (OGRMultiPolygon* geom, mapnik::feature_ptr feature); - static void convert_multipolygon_2 (OGRMultiPolygon* geom, mapnik::feature_ptr feature); }; #endif // OGR_CONVERTER_HPP diff --git a/plugins/input/ogr/ogr_datasource.cpp b/plugins/input/ogr/ogr_datasource.cpp index 7fbca6486..230244655 100644 --- a/plugins/input/ogr/ogr_datasource.cpp +++ b/plugins/input/ogr/ogr_datasource.cpp @@ -66,8 +66,6 @@ ogr_datasource::ogr_datasource(parameters const& params, bool bind) throw datasource_exception("missing or parameter"); } - multiple_geometries_ = *params.get("multiple_geometries", false); - if (string) { dataset_name_ = *string; @@ -403,16 +401,16 @@ featureset_ptr ogr_datasource::features(query const& q) const *layer, filter, index_name_, - desc_.get_encoding(), - multiple_geometries_)); + desc_.get_encoding() + )); } else { return featureset_ptr(new ogr_featureset (*dataset_, *layer, q.get_bbox(), - desc_.get_encoding(), - multiple_geometries_)); + desc_.get_encoding() + )); } } @@ -435,8 +433,8 @@ featureset_ptr ogr_datasource::features_at_point(coord2d const& pt) const *layer, filter, index_name_, - desc_.get_encoding(), - multiple_geometries_)); + desc_.get_encoding() + )); } else { @@ -447,8 +445,8 @@ featureset_ptr ogr_datasource::features_at_point(coord2d const& pt) const return featureset_ptr(new ogr_featureset (*dataset_, *layer, point, - desc_.get_encoding(), - multiple_geometries_)); + desc_.get_encoding() + )); } } diff --git a/plugins/input/ogr/ogr_datasource.hpp b/plugins/input/ogr/ogr_datasource.hpp index 25612f173..694af5d7f 100644 --- a/plugins/input/ogr/ogr_datasource.hpp +++ b/plugins/input/ogr/ogr_datasource.hpp @@ -58,7 +58,6 @@ private: mutable ogr_layer_ptr layer_; mutable std::string layer_name_; mutable mapnik::layer_descriptor desc_; - bool multiple_geometries_; mutable bool indexed_; }; diff --git a/plugins/input/ogr/ogr_featureset.cpp b/plugins/input/ogr/ogr_featureset.cpp index 9f3efc05b..2e916a4bb 100644 --- a/plugins/input/ogr/ogr_featureset.cpp +++ b/plugins/input/ogr/ogr_featureset.cpp @@ -49,14 +49,12 @@ using mapnik::feature_factory; ogr_featureset::ogr_featureset(OGRDataSource & dataset, OGRLayer & layer, OGRGeometry & extent, - const std::string& encoding, - const bool multiple_geometries) + const std::string& encoding) : dataset_(dataset), layer_(layer), layerdef_(layer.GetLayerDefn()), tr_(new transcoder(encoding)), fidcolumn_(layer_.GetFIDColumn ()), - multiple_geometries_(multiple_geometries), count_(0) { layer_.SetSpatialFilter (&extent); @@ -65,14 +63,12 @@ ogr_featureset::ogr_featureset(OGRDataSource & dataset, ogr_featureset::ogr_featureset(OGRDataSource & dataset, OGRLayer & layer, const mapnik::box2d & extent, - const std::string& encoding, - const bool multiple_geometries) + const std::string& encoding) : dataset_(dataset), layer_(layer), layerdef_(layer.GetLayerDefn()), tr_(new transcoder(encoding)), fidcolumn_(layer_.GetFIDColumn()), - multiple_geometries_(multiple_geometries), count_(0) { layer_.SetSpatialFilterRect (extent.minx(), @@ -99,7 +95,7 @@ feature_ptr ogr_featureset::next() OGRGeometry* geom = (*feat)->GetGeometryRef(); if (geom && ! geom->IsEmpty()) { - ogr_converter::convert_geometry(geom, feature, multiple_geometries_); + ogr_converter::convert_geometry(geom, feature); } #ifdef MAPNIK_DEBUG else diff --git a/plugins/input/ogr/ogr_featureset.hpp b/plugins/input/ogr/ogr_featureset.hpp index 0f4fbeb1c..7e30a1ab1 100644 --- a/plugins/input/ogr/ogr_featureset.hpp +++ b/plugins/input/ogr/ogr_featureset.hpp @@ -40,14 +40,12 @@ public: ogr_featureset(OGRDataSource & dataset, OGRLayer & layer, OGRGeometry & extent, - const std::string& encoding, - const bool multiple_geometries); + const std::string& encoding); ogr_featureset(OGRDataSource & dataset, OGRLayer & layer, const mapnik::box2d & extent, - const std::string& encoding, - const bool multiple_geometries); + const std::string& encoding); virtual ~ogr_featureset(); mapnik::feature_ptr next(); @@ -60,7 +58,6 @@ private: OGRFeatureDefn* layerdef_; boost::scoped_ptr tr_; const char* fidcolumn_; - bool multiple_geometries_; mutable int count_; }; diff --git a/plugins/input/ogr/ogr_index_featureset.cpp b/plugins/input/ogr/ogr_index_featureset.cpp index 2bace05bb..399a0aa65 100644 --- a/plugins/input/ogr/ogr_index_featureset.cpp +++ b/plugins/input/ogr/ogr_index_featureset.cpp @@ -56,15 +56,13 @@ ogr_index_featureset::ogr_index_featureset(OGRDataSource & dataset, OGRLayer & layer, const filterT& filter, const std::string& index_file, - const std::string& encoding, - const bool multiple_geometries) + const std::string& encoding) : dataset_(dataset), layer_(layer), layerdef_(layer.GetLayerDefn()), filter_(filter), tr_(new transcoder(encoding)), - fidcolumn_(layer_.GetFIDColumn()), - multiple_geometries_(multiple_geometries) + fidcolumn_(layer_.GetFIDColumn()) { boost::optional memory = mapnik::mapped_memory_cache::find(index_file.c_str(),true); @@ -108,7 +106,7 @@ feature_ptr ogr_index_featureset::next() OGRGeometry* geom=(*feat)->GetGeometryRef(); if (geom && !geom->IsEmpty()) { - ogr_converter::convert_geometry (geom, feature, multiple_geometries_); + ogr_converter::convert_geometry (geom, feature); } #ifdef MAPNIK_DEBUG else diff --git a/plugins/input/ogr/ogr_index_featureset.hpp b/plugins/input/ogr/ogr_index_featureset.hpp index 03ab3626c..1d76f914b 100644 --- a/plugins/input/ogr/ogr_index_featureset.hpp +++ b/plugins/input/ogr/ogr_index_featureset.hpp @@ -36,8 +36,7 @@ public: OGRLayer& layer, const filterT& filter, const std::string& index_file, - const std::string& encoding, - const bool multiple_geometries); + const std::string& encoding); virtual ~ogr_index_featureset(); mapnik::feature_ptr next(); @@ -53,7 +52,6 @@ private: std::vector::iterator itr_; boost::scoped_ptr tr_; const char* fidcolumn_; - bool multiple_geometries_; }; #endif // OGR_INDEX_FEATURESET_HPP diff --git a/plugins/input/postgis/build.py b/plugins/input/postgis/build.py index a1e8563c6..c1d4a00a6 100644 --- a/plugins/input/postgis/build.py +++ b/plugins/input/postgis/build.py @@ -33,15 +33,23 @@ postgis_src = Split( """ ) -libraries = ['pq'] +# clear out and rebuild libs +plugin_env['LIBS'] = ['pq'] # Link Library to Dependencies -libraries.append('mapnik') -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['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'])) diff --git a/plugins/input/postgis/postgis_datasource.cpp b/plugins/input/postgis/postgis_datasource.cpp index 9b2c641c1..2d0d642f9 100644 --- a/plugins/input/postgis/postgis_datasource.cpp +++ b/plugins/input/postgis/postgis_datasource.cpp @@ -87,8 +87,6 @@ postgis_datasource::postgis_datasource(parameters const& params, bool bind) { if (table_.empty()) throw mapnik::datasource_exception("Postgis Plugin: missing parameter"); - multiple_geometries_ = *params_.get("multiple_geometries",false); - boost::optional ext = params_.get("extent"); if (ext) extent_initialized_ = extent_.from_string(*ext); @@ -517,7 +515,7 @@ featureset_ptr postgis_datasource::features(const query& q) const unsigned num_attr = props.size(); if (!key_field_.empty()) ++num_attr; - return boost::make_shared(rs,desc_.get_encoding(),multiple_geometries_,!key_field_.empty(),num_attr); + return boost::make_shared(rs,desc_.get_encoding(), !key_field_.empty(),num_attr); } else { @@ -585,7 +583,7 @@ featureset_ptr postgis_datasource::features_at_point(coord2d const& pt) const } boost::shared_ptr rs = get_resultset(conn, s.str()); - return boost::make_shared(rs,desc_.get_encoding(),multiple_geometries_,!key_field_.empty(),size); + return boost::make_shared(rs,desc_.get_encoding(), !key_field_.empty(),size); } } return featureset_ptr(); diff --git a/plugins/input/postgis/postgis_datasource.hpp b/plugins/input/postgis/postgis_datasource.hpp index 8ad42e4f9..0ad00df9c 100644 --- a/plugins/input/postgis/postgis_datasource.hpp +++ b/plugins/input/postgis/postgis_datasource.hpp @@ -69,7 +69,6 @@ class postgis_datasource : public datasource mutable mapnik::box2d extent_; mutable layer_descriptor desc_; ConnectionCreator creator_; - bool multiple_geometries_; const std::string bbox_token_; const std::string scale_denom_token_; bool persist_connection_; diff --git a/plugins/input/postgis/postgis_featureset.cpp b/plugins/input/postgis/postgis_featureset.cpp index 84a877248..087047ce5 100644 --- a/plugins/input/postgis/postgis_featureset.cpp +++ b/plugins/input/postgis/postgis_featureset.cpp @@ -49,11 +49,9 @@ using mapnik::feature_factory; postgis_featureset::postgis_featureset(boost::shared_ptr const& rs, std::string const& encoding, - bool multiple_geometries, bool key_field=false, unsigned num_attrs=0) : rs_(rs), - multiple_geometries_(multiple_geometries), num_attrs_(num_attrs), tr_(new transcoder(encoding)), totalGeomSize_(0), @@ -103,7 +101,7 @@ feature_ptr postgis_featureset::next() // parse geometry int size = rs_->getFieldLength(0); const char *data = rs_->getValue(0); - geometry_utils::from_wkb(feature->paths(),data,size,multiple_geometries_); + geometry_utils::from_wkb(feature->paths(), data, size); totalGeomSize_+=size; for ( ;pos rs_; - bool multiple_geometries_; unsigned num_attrs_; boost::scoped_ptr tr_; int totalGeomSize_; @@ -53,7 +52,6 @@ private: public: postgis_featureset(boost::shared_ptr const& rs, std::string const& encoding, - bool multiple_geometries, bool key_field, unsigned num_attrs); mapnik::feature_ptr next(); diff --git a/plugins/input/shape/shape_featureset.cpp b/plugins/input/shape/shape_featureset.cpp index 9a6753b52..779c3869d 100644 --- a/plugins/input/shape/shape_featureset.cpp +++ b/plugins/input/shape/shape_featureset.cpp @@ -248,55 +248,25 @@ feature_ptr shape_featureset::next() } case shape_io::shape_polyline: - { - geometry_type* line = shape_.read_polyline(); - feature->add_geometry(line); - ++count_; - break; - } - case shape_io::shape_polylinem: - { - geometry_type* line = shape_.read_polylinem(); - feature->add_geometry(line); - ++count_; - break; - } - case shape_io::shape_polylinez: { - geometry_type* line = shape_.read_polylinez(); - feature->add_geometry(line); + shape_.read_polyline(feature->paths()); ++count_; break; } - + case shape_io::shape_polygon: - { - geometry_type* poly = shape_.read_polygon(); - feature->add_geometry(poly); - ++count_; - break; - } - case shape_io::shape_polygonm: - { - geometry_type* poly = shape_.read_polygonm(); - feature->add_geometry(poly); - ++count_; - break; - } - case shape_io::shape_polygonz: { - geometry_type* poly = shape_.read_polygonz(); - feature->add_geometry(poly); + shape_.read_polygon(feature->paths()); ++count_; break; } } } - + feature->set_id(shape_.id_); if (attr_ids_.size()) { diff --git a/plugins/input/shape/shape_index_featureset.cpp b/plugins/input/shape/shape_index_featureset.cpp index b25e8c644..0c0fcadc5 100644 --- a/plugins/input/shape/shape_index_featureset.cpp +++ b/plugins/input/shape/shape_index_featureset.cpp @@ -193,49 +193,18 @@ feature_ptr shape_index_featureset::next() } case shape_io::shape_polyline: - { - geometry_type* line = shape_.read_polyline(); - feature->add_geometry(line); - ++count_; - break; - } - case shape_io::shape_polylinem: - { - geometry_type* line = shape_.read_polylinem(); - feature->add_geometry(line); - ++count_; - break; - } - case shape_io::shape_polylinez: { - geometry_type* line = shape_.read_polylinez(); - feature->add_geometry(line); + shape_.read_polyline(feature->paths()); ++count_; break; } - case shape_io::shape_polygon: - { - geometry_type* poly = shape_.read_polygon(); - feature->add_geometry(poly); - ++count_; - break; - } - case shape_io::shape_polygonm: - { - geometry_type* poly = shape_.read_polygonm(); - feature->add_geometry(poly); - ++count_; - break; - } - case shape_io::shape_polygonz: { - geometry_type* poly = shape_.read_polygonz(); - feature->add_geometry(poly); + shape_.read_polygon(feature->paths()); ++count_; break; } diff --git a/plugins/input/shape/shape_io.cpp b/plugins/input/shape/shape_io.cpp index 04aa48814..1fc570c24 100644 --- a/plugins/input/shape/shape_io.cpp +++ b/plugins/input/shape/shape_io.cpp @@ -106,18 +106,16 @@ dbf_file& shape_io::dbf() return dbf_; } -geometry_type* shape_io::read_polyline() +void shape_io::read_polyline(mapnik::geometry_container & geom) { shape_file::record_type record(reclength_ * 2 - 36); shp_.read_record(record); int num_parts = record.read_ndr_integer(); int num_points = record.read_ndr_integer(); - geometry_type* line = new geometry_type(mapnik::LineString); - line->set_capacity(num_points + num_parts); if (num_parts == 1) { - line->set_capacity(num_points + 1); + geometry_type* line = new geometry_type(mapnik::LineString); record.skip(4); double x = record.read_double(); double y = record.read_double(); @@ -128,6 +126,7 @@ geometry_type* shape_io::read_polyline() y = record.read_double(); line->line_to(x, y); } + geom.push_back(line); } else { @@ -140,6 +139,7 @@ geometry_type* shape_io::read_polyline() int start, end; for (int k = 0; k < num_parts; ++k) { + geometry_type* line = new geometry_type(mapnik::LineString); start = parts[k]; if (k == num_parts - 1) { @@ -160,135 +160,9 @@ geometry_type* shape_io::read_polyline() y = record.read_double(); line->line_to(x, y); } + geom.push_back(line); } } - return line; -} - -geometry_type* shape_io::read_polylinem() -{ - shape_file::record_type record(reclength_ * 2 - 36); - shp_.read_record(record); - - int num_parts = record.read_ndr_integer(); - int num_points = record.read_ndr_integer(); - geometry_type* line = new geometry_type(mapnik::LineString); - line->set_capacity(num_points + num_parts); - if (num_parts == 1) - { - record.skip(4); - double x = record.read_double(); - double y = record.read_double(); - line->move_to(x, y); - for (int i = 1; i < num_points; ++i) - { - x = record.read_double(); - y = record.read_double(); - line->line_to(x, y); - } - } - else - { - std::vector parts(num_parts); - for (int i = 0; i < num_parts; ++i) - { - parts[i] = record.read_ndr_integer(); - } - - int start, end; - for (int k = 0; k < num_parts; ++k) - { - start = parts[k]; - if (k == num_parts - 1) - { - end = num_points; - } - else - { - end = parts[k + 1]; - } - - double x = record.read_double(); - double y = record.read_double(); - line->move_to(x, y); - - for (int j = start + 1; j < end; ++j) - { - x = record.read_double(); - y = record.read_double(); - line->line_to(x, y); - } - } - } - - // m-range - //double m0=record.read_double(); - //double m1=record.read_double(); - - //for (int i=0;iset_capacity(num_points + num_parts); - if (num_parts == 1) - { - record.skip(4); - double x = record.read_double(); - double y = record.read_double(); - line->move_to(x, y); - for (int i = 1; i < num_points; ++i) - { - x = record.read_double(); - y = record.read_double(); - line->line_to(x, y); - } - } - else - { - std::vector parts(num_parts); - for (int i = 0; i < num_parts; ++i) - { - parts[i] = record.read_ndr_integer(); - } - - int start, end; - for (int k = 0; k < num_parts; ++k) - { - start = parts[k]; - if (k == num_parts - 1) - { - end = num_points; - } - else - { - end = parts[k + 1]; - } - - double x = record.read_double(); - double y = record.read_double(); - line->move_to(x, y); - - for (int j = start + 1; j < end; ++j) - { - x = record.read_double(); - y = record.read_double(); - line->line_to(x, y); - } - } - } - // z-range //double z0=record.read_double(); //double z1=record.read_double(); @@ -306,10 +180,9 @@ geometry_type* shape_io::read_polylinez() // double m=record.read_double(); //} - return line; } -geometry_type* shape_io::read_polygon() +void shape_io::read_polygon(mapnik::geometry_container & geom) { shape_file::record_type record(reclength_ * 2 - 36); shp_.read_record(record); @@ -317,15 +190,17 @@ geometry_type* shape_io::read_polygon() int num_parts = record.read_ndr_integer(); int num_points = record.read_ndr_integer(); std::vector parts(num_parts); - geometry_type* poly = new geometry_type(mapnik::Polygon); - poly->set_capacity(num_points + num_parts); + for (int i = 0; i < num_parts; ++i) { parts[i] = record.read_ndr_integer(); } + geometry_type* poly = new geometry_type(mapnik::Polygon); + for (int k = 0; k < num_parts; k++) { + int start = parts[k]; int end; if (k == num_parts - 1) @@ -339,6 +214,13 @@ geometry_type* shape_io::read_polygon() double x = record.read_double(); double y = record.read_double(); + + if (k > 0 && !poly->hit_test(x,y,0)) + { + geom.push_back(poly); + poly = new geometry_type(mapnik::Polygon); + } + poly->move_to(x, y); for (int j=start+1;jline_to(x, y); } } - return poly; -} - -geometry_type* shape_io::read_polygonm() -{ - shape_file::record_type record(reclength_ * 2 - 36); - shp_.read_record(record); - - int num_parts = record.read_ndr_integer(); - int num_points = record.read_ndr_integer(); - std::vector parts(num_parts); - geometry_type* poly = new geometry_type(mapnik::Polygon); - poly->set_capacity(num_points + num_parts); - for (int i = 0; i < num_parts; ++i) - { - parts[i] = record.read_ndr_integer(); - } - - for (int k = 0; k < num_parts; k++) - { - int start = parts[k]; - int end; - if (k == num_parts - 1) - { - end = num_points; - } - else - { - end = parts[k + 1]; - } - - double x = record.read_double(); - double y = record.read_double(); - poly->move_to(x, y); - - for (int j = start + 1; j < end; j++) - { - x = record.read_double(); - y = record.read_double(); - poly->line_to(x, y); - } - } - - // m-range - //double m0=record.read_double(); - //double m1=record.read_double(); - - //for (int i=0;i parts(num_parts); - geometry_type* poly = new geometry_type(mapnik::Polygon); - poly->set_capacity(num_points + num_parts); - for (int i = 0; i < num_parts; ++i) - { - parts[i] = record.read_ndr_integer(); - } - - for (int k = 0; k < num_parts; k++) - { - int start = parts[k]; - int end; - if (k == num_parts - 1) - { - end = num_points; - } - else - { - end = parts[k + 1]; - } - - double x = record.read_double(); - double y = record.read_double(); - poly->move_to(x, y); - - for (int j = start + 1; j < end; j++) - { - x = record.read_double(); - y = record.read_double(); - poly->line_to(x, y); - } - } + geom.push_back(poly); // z-range //double z0=record.read_double(); //double z1=record.read_double(); @@ -458,6 +248,6 @@ geometry_type* shape_io::read_polygonz() //{ // double m=record.read_double(); //} - - return poly; } + + diff --git a/plugins/input/shape/shape_io.hpp b/plugins/input/shape/shape_io.hpp index 1623402df..1421ec0ab 100644 --- a/plugins/input/shape/shape_io.hpp +++ b/plugins/input/shape/shape_io.hpp @@ -23,6 +23,8 @@ #ifndef SHAPE_IO_HPP #define SHAPE_IO_HPP +// mapnik +#include // boost #include #include @@ -56,9 +58,8 @@ public: ~shape_io(); shape_file& shp(); - //shape_file& shx(); dbf_file& dbf(); - + inline boost::shared_ptr& index() { return index_; @@ -72,16 +73,10 @@ public: void move_to(int id); int type() const; const box2d& current_extent() const; - mapnik::geometry_type* read_polyline(); - mapnik::geometry_type* read_polylinem(); - mapnik::geometry_type* read_polylinez(); - mapnik::geometry_type* read_polygon(); - mapnik::geometry_type* read_polygonm(); - mapnik::geometry_type* read_polygonz(); - + void read_polyline(mapnik::geometry_container & geom); + void read_polygon(mapnik::geometry_container & geom); unsigned type_; shape_file shp_; - //shape_file shx_; dbf_file dbf_; boost::shared_ptr index_; unsigned reclength_; @@ -89,7 +84,6 @@ public: box2d cur_extent_; static const std::string SHP; - //static const std::string SHX; static const std::string DBF; static const std::string INDEX; }; diff --git a/plugins/input/sqlite/sqlite_datasource.cpp b/plugins/input/sqlite/sqlite_datasource.cpp index 7946dfead..14b6a068c 100644 --- a/plugins/input/sqlite/sqlite_datasource.cpp +++ b/plugins/input/sqlite/sqlite_datasource.cpp @@ -62,6 +62,7 @@ sqlite_datasource::sqlite_datasource(parameters const& params, bool bind) key_field_(*params_.get("key_field", "")), row_offset_(*params_.get("row_offset", 0)), row_limit_(*params_.get("row_limit", 0)), + intersects_token_("!intersects!"), desc_(*params_.get("type"), *params_.get("encoding", "utf-8")), format_(mapnik::wkbAuto) { @@ -102,7 +103,6 @@ void sqlite_datasource::bind() const throw datasource_exception("Sqlite Plugin: " + dataset_name_ + " does not exist"); } - multiple_geometries_ = *params_.get("multiple_geometries", false); use_spatial_index_ = *params_.get("use_spatial_index", true); // TODO - remove this option once all datasources have an indexing api @@ -186,7 +186,8 @@ void sqlite_datasource::bind() const if (using_subquery_) { std::ostringstream s; - s << "SELECT " << fields_ << " FROM (" << table_ << ") LIMIT 1"; + std::string query = populate_tokens(table_); + s << "SELECT " << fields_ << " FROM (" << query << ") LIMIT 1"; found_types_via_subquery = sqlite_utils::detect_types_from_subquery(s.str(),geometry_field_,desc_,dataset_); } @@ -225,7 +226,12 @@ void sqlite_datasource::bind() const if (geometry_field_.empty()) { - throw datasource_exception("Sqlite Plugin: cannot detect geometry_field, please supply the name of the geometry_field to use."); + std::ostringstream s; + s << "Sqlite Plugin: unable to detect the column " + << "containing a valid geometry on table '" << geometry_table_ << "'. " + << "Please provide a column name by passing the 'geometry_field' option " + << "or indicate a different spatial table to use by passing the 'geometry_table' option"; + throw datasource_exception(s.str()); } if (index_table_.empty()) @@ -302,6 +308,7 @@ void sqlite_datasource::bind() const { // TODO - clean this up - reducing arguments + std::string query = populate_tokens(table_); if (!sqlite_utils::detect_extent(dataset_, has_spatial_index_, extent_, @@ -310,7 +317,7 @@ void sqlite_datasource::bind() const geometry_field_, geometry_table_, key_field_, - table_)) + query)) { std::ostringstream s; s << "Sqlite Plugin: extent could not be determined for table '" @@ -324,6 +331,17 @@ void sqlite_datasource::bind() const is_bound_ = true; } +std::string sqlite_datasource::populate_tokens(const std::string& sql) const +{ + std::string populated_sql = sql; + if (boost::algorithm::ifind_first(populated_sql, intersects_token_)) + { + // replace with dummy comparison that is true + boost::algorithm::ireplace_first(populated_sql, intersects_token_, "1=1"); + } + return populated_sql; +} + sqlite_datasource::~sqlite_datasource() { } @@ -461,23 +479,21 @@ featureset_ptr sqlite_datasource::features(query const& q) const s << " FROM "; - std::string query (table_); + std::string query(table_); if (! key_field_.empty() && has_spatial_index_) { - std::ostringstream spatial_sql; - spatial_sql << std::setprecision(16); - spatial_sql << " WHERE " << key_field_ << " IN (SELECT pkid FROM " << index_table_; - spatial_sql << " WHERE xmax>=" << e.minx() << " AND xmin<=" << e.maxx() ; - spatial_sql << " AND ymax>=" << e.miny() << " AND ymin<=" << e.maxy() << ")"; - if (boost::algorithm::ifind_first(query, "WHERE")) - { - boost::algorithm::ireplace_first(query, "WHERE", spatial_sql.str() + " AND "); - } - else if (boost::algorithm::ifind_first(query, geometry_table_)) - { - boost::algorithm::ireplace_first(query, table_, table_ + " " + spatial_sql.str()); - } + // TODO - debug warn if fails + sqlite_utils::apply_spatial_filter(query, + e, + table_, + key_field_, + index_table_, + geometry_table_, + intersects_token_); } + else + { + query = populate_tokens(table_); } s << query ; @@ -502,7 +518,6 @@ featureset_ptr sqlite_datasource::features(query const& q) const return boost::make_shared(rs, desc_.get_encoding(), format_, - multiple_geometries_, using_subquery_); } @@ -541,19 +556,18 @@ featureset_ptr sqlite_datasource::features_at_point(coord2d const& pt) const if (! key_field_.empty() && has_spatial_index_) { - std::ostringstream spatial_sql; - spatial_sql << std::setprecision(16); - spatial_sql << " WHERE " << key_field_ << " IN (SELECT pkid FROM " << index_table_; - spatial_sql << " WHERE xmax>=" << e.minx() << " AND xmin<=" << e.maxx() ; - spatial_sql << " AND ymax>=" << e.miny() << " AND ymin<=" << e.maxy() << ")"; - if (boost::algorithm::ifind_first(query, "WHERE")) - { - boost::algorithm::ireplace_first(query, "WHERE", spatial_sql.str() + " AND "); - } - else if (boost::algorithm::ifind_first(query, geometry_table_)) - { - boost::algorithm::ireplace_first(query, table_, table_ + " " + spatial_sql.str()); - } + // TODO - debug warn if fails + sqlite_utils::apply_spatial_filter(query, + e, + table_, + key_field_, + index_table_, + geometry_table_, + intersects_token_); + } + else + { + query = populate_tokens(table_); } s << query ; @@ -577,9 +591,8 @@ featureset_ptr sqlite_datasource::features_at_point(coord2d const& pt) const return boost::make_shared(rs, desc_.get_encoding(), format_, - multiple_geometries_, using_subquery_); } - + return featureset_ptr(); } diff --git a/plugins/input/sqlite/sqlite_datasource.hpp b/plugins/input/sqlite/sqlite_datasource.hpp index afecfcb89..f705f762d 100644 --- a/plugins/input/sqlite/sqlite_datasource.hpp +++ b/plugins/input/sqlite/sqlite_datasource.hpp @@ -51,6 +51,11 @@ public: void bind() const; private: + + // FIXME: remove mutable qualifier from data members + // by factoring out bind() logic out from + // datasource impl !!! + mutable mapnik::box2d extent_; mutable bool extent_initialized_; int type_; @@ -65,9 +70,10 @@ private: mutable std::string key_field_; mutable int row_offset_; mutable int row_limit_; + // TODO - also add to postgis.input + const std::string intersects_token_; mutable mapnik::layer_descriptor desc_; mutable mapnik::wkbFormat format_; - mutable bool multiple_geometries_; mutable bool use_spatial_index_; mutable bool has_spatial_index_; mutable bool using_subquery_; @@ -76,6 +82,7 @@ private: // Fill init_statements with any statements // needed to attach auxillary databases void parse_attachdb(std::string const& attachdb) const; + std::string populate_tokens(const std::string& sql) const; }; #endif // MAPNIK_SQLITE_DATASOURCE_HPP diff --git a/plugins/input/sqlite/sqlite_featureset.cpp b/plugins/input/sqlite/sqlite_featureset.cpp index 1cf0d8110..f92a8ba46 100644 --- a/plugins/input/sqlite/sqlite_featureset.cpp +++ b/plugins/input/sqlite/sqlite_featureset.cpp @@ -47,12 +47,10 @@ using mapnik::feature_factory; sqlite_featureset::sqlite_featureset(boost::shared_ptr rs, std::string const& encoding, mapnik::wkbFormat format, - bool multiple_geometries, bool using_subquery) : rs_(rs), tr_(new transcoder(encoding)), format_(format), - multiple_geometries_(multiple_geometries), using_subquery_(using_subquery) { } @@ -75,8 +73,8 @@ feature_ptr sqlite_featureset::next() int feature_id = rs_->column_integer(1); feature_ptr feature(feature_factory::create(feature_id)); - geometry_utils::from_wkb(feature->paths(), data, size, multiple_geometries_, format_); - + geometry_utils::from_wkb(feature->paths(), data, size, format_); + for (int i = 2; i < rs_->column_count(); ++i) { const int type_oid = rs_->column_type(i); diff --git a/plugins/input/sqlite/sqlite_featureset.hpp b/plugins/input/sqlite/sqlite_featureset.hpp index 313cadb38..4ec7472ba 100644 --- a/plugins/input/sqlite/sqlite_featureset.hpp +++ b/plugins/input/sqlite/sqlite_featureset.hpp @@ -42,7 +42,6 @@ public: sqlite_featureset(boost::shared_ptr rs, std::string const& encoding, mapnik::wkbFormat format, - bool multiple_geometries, bool using_subquery); virtual ~sqlite_featureset(); mapnik::feature_ptr next(); @@ -51,7 +50,6 @@ private: boost::shared_ptr rs_; boost::scoped_ptr tr_; mapnik::wkbFormat format_; - bool multiple_geometries_; bool using_subquery_; }; diff --git a/plugins/input/sqlite/sqlite_utils.hpp b/plugins/input/sqlite/sqlite_utils.hpp index 1e3ede064..6021d26ca 100644 --- a/plugins/input/sqlite/sqlite_utils.hpp +++ b/plugins/input/sqlite/sqlite_utils.hpp @@ -108,6 +108,42 @@ public: //} } + static bool apply_spatial_filter(std::string & query, + mapnik::box2d const& e, + std::string const& table, + std::string const& key_field, + std::string const& index_table, + std::string const& geometry_table, + std::string const& intersects_token) + { + std::ostringstream spatial_sql; + spatial_sql << std::setprecision(16); + spatial_sql << key_field << " IN (SELECT pkid FROM " << index_table; + spatial_sql << " WHERE xmax>=" << e.minx() << " AND xmin<=" << e.maxx() ; + spatial_sql << " AND ymax>=" << e.miny() << " AND ymin<=" << e.maxy() << ")"; + if (boost::algorithm::ifind_first(query, intersects_token)) + { + boost::algorithm::ireplace_all(query, intersects_token, spatial_sql.str()); + return true; + } + // substitute first WHERE found if not using JOIN + // (because we can't know the WHERE is on the right table) + else if (boost::algorithm::ifind_first(query, "WHERE") + && !boost::algorithm::ifind_first(query, "JOIN")) + { + std::string replace(" WHERE " + spatial_sql.str() + " AND "); + boost::algorithm::ireplace_first(query, "WHERE", replace); + return true; + } + // fallback to appending spatial filter at end of query + else if (boost::algorithm::ifind_first(query, geometry_table)) + { + query = table + " WHERE " + spatial_sql.str(); + return true; + } + return false; + } + static void get_tables(boost::shared_ptr ds, std::vector & tables) { @@ -151,11 +187,11 @@ public: while (rs->is_valid() && rs->step_next()) { int size; - const char* data = (const char*) rs->column_blob(0, size); + const char* data = static_cast(rs->column_blob(0, size)); if (data) { boost::ptr_vector paths; - mapnik::geometry_utils::from_wkb(paths, data, size, false, mapnik::wkbAuto); + mapnik::geometry_utils::from_wkb(paths, data, size, mapnik::wkbAuto); for (unsigned i=0; i const& bbox = paths[i].envelope(); @@ -241,41 +277,47 @@ public: if (data) { boost::ptr_vector paths; - // TODO - contraint fails if multiple_geometries = true - bool multiple_geometries = false; - mapnik::geometry_utils::from_wkb(paths, data, size, multiple_geometries, mapnik::wkbAuto); + mapnik::geometry_utils::from_wkb(paths, data, size, mapnik::wkbAuto); + mapnik::box2d bbox; for (unsigned i=0; i const& bbox = paths[i].envelope(); - if (bbox.valid()) + if (i==0) { - - ps.bind(bbox); - - const int type_oid = rs->column_type(1); - if (type_oid != SQLITE_INTEGER) - { - std::ostringstream error_msg; - error_msg << "Sqlite Plugin: invalid type for key field '" - << rs->column_name(1) << "' when creating index '" << index_table - << "' type was: " << type_oid << ""; - throw mapnik::datasource_exception(error_msg.str()); - } - - const sqlite_int64 pkid = rs->column_integer64(1); - ps.bind(pkid); + bbox = paths[i].envelope(); } else + { + bbox.expand_to_include(paths[i].envelope()); + } + } + if (bbox.valid()) + { + + ps.bind(bbox); + + const int type_oid = rs->column_type(1); + if (type_oid != SQLITE_INTEGER) { std::ostringstream error_msg; - error_msg << "SQLite Plugin: encountered invalid bbox at '" - << rs->column_name(1) << "' == " << rs->column_integer64(1); + error_msg << "Sqlite Plugin: invalid type for key field '" + << rs->column_name(1) << "' when creating index '" << index_table + << "' type was: " << type_oid << ""; throw mapnik::datasource_exception(error_msg.str()); } - ps.step_next(); - one_success = true; + const sqlite_int64 pkid = rs->column_integer64(1); + ps.bind(pkid); } + else + { + std::ostringstream error_msg; + error_msg << "SQLite Plugin: encountered invalid bbox at '" + << rs->column_name(1) << "' == " << rs->column_integer64(1); + throw mapnik::datasource_exception(error_msg.str()); + } + + ps.step_next(); + one_success = true; } } } @@ -320,13 +362,11 @@ public: while (rs->is_valid() && rs->step_next()) { int size; - const char* data = (const char*) rs->column_blob(0, size); + const char* data = static_cast(rs->column_blob(0, size)); if (data) { boost::ptr_vector paths; - // TODO - contraint fails if multiple_geometries = true - bool multiple_geometries = false; - mapnik::geometry_utils::from_wkb(paths, data, size, multiple_geometries, mapnik::wkbAuto); + mapnik::geometry_utils::from_wkb(paths, data, size, mapnik::wkbAuto); for (unsigned i=0; i const& bbox = paths[i].envelope(); @@ -568,6 +608,7 @@ public: // PRAGMA table_info is used so here we assume the column is a string // which is a lesser evil than altogether dropping the column desc.add_descriptor(mapnik::attribute_descriptor(fld_name, mapnik::String)); + break; case SQLITE_BLOB: if (geometry_field.empty() diff --git a/src/agg/process_building_symbolizer.cpp b/src/agg/process_building_symbolizer.cpp index a9b8b0dbd..f28b17fdc 100644 --- a/src/agg/process_building_symbolizer.cpp +++ b/src/agg/process_building_symbolizer.cpp @@ -25,6 +25,7 @@ #include #include #include +#include // boost #include @@ -66,7 +67,13 @@ void agg_renderer::process(building_symbolizer const& sym, ras_ptr->reset(); ras_ptr->gamma(agg::gamma_linear()); - double height = sym.height() * scale_factor_; + double height = 0.0; + expression_ptr height_expr = sym.height(); + if (height_expr) + { + value_type result = boost::apply_visitor(evaluate(feature), *height_expr); + height = result.to_double() * scale_factor_; + } for (unsigned i=0;i::process(building_symbolizer const& sym, std::deque face_segments; double x0(0); double y0(0); + + geom.rewind(0); unsigned cm = geom.vertex(&x0,&y0); for (unsigned j=1;j::process(building_symbolizer const& sym, roof->line_to(x,y+height); } } + path_type path(t_,*frame,prj_trans); agg::conv_stroke stroke(path); ras_ptr->add_path(stroke); diff --git a/src/agg/process_polygon_symbolizer.cpp b/src/agg/process_polygon_symbolizer.cpp index c376d9544..a3c3f9d1d 100644 --- a/src/agg/process_polygon_symbolizer.cpp +++ b/src/agg/process_polygon_symbolizer.cpp @@ -62,7 +62,7 @@ void agg_renderer::process(polygon_symbolizer const& sym, renderer ren(renb); ras_ptr->reset(); - ras_ptr->gamma(agg::gamma_linear(0.0, sym.get_gamma())); + ras_ptr->gamma(agg::gamma_power(sym.get_gamma())); metawriter_with_properties writer = sym.get_metawriter(); for (unsigned i=0;i::process(text_symbolizer const& sym, if (geom.num_points() == 0) continue; // don't bother with empty geometries - if ((geom.type() == Polygon || geom.type() == MultiPolygon) && sym.get_minimum_path_length() > 0) + if ((geom.type() == Polygon) && sym.get_minimum_path_length() > 0) { // TODO - find less costly method than fetching full envelope box2d gbox = t_.forward(geom.envelope(),prj_trans); diff --git a/src/build.py b/src/build.py index 927cda481..f3f6f42a7 100644 --- a/src/build.py +++ b/src/build.py @@ -106,6 +106,7 @@ source = Split( color.cpp box2d.cpp datasource_cache.cpp + deepcopy.cpp expression_string.cpp filter_factory.cpp feature_type_style.cpp @@ -193,6 +194,20 @@ if env['RENDERING_STATS']: else: source.insert(0,processor_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( """ diff --git a/src/cairo_renderer.cpp b/src/cairo_renderer.cpp index f47d78e7e..1609aed72 100644 --- a/src/cairo_renderer.cpp +++ b/src/cairo_renderer.cpp @@ -779,7 +779,13 @@ void cairo_renderer_base::process(building_symbolizer const& sym, cairo_context context(context_); color const& fill = sym.get_fill(); - double height = 0.7071 * sym.height(); // height in meters + double height = 0.0; + expression_ptr height_expr = sym.height(); + if (height_expr) + { + value_type result = boost::apply_visitor(evaluate(feature), *height_expr); + height = 0.7071 * result.to_double(); + } for (unsigned i = 0; i < feature.num_geometries(); ++i) { @@ -792,6 +798,8 @@ void cairo_renderer_base::process(building_symbolizer const& sym, std::deque face_segments; double x0(0); double y0(0); + + geom.rewind(0); unsigned cm = geom.vertex(&x0, &y0); for (unsigned j = 1; j < geom.num_points(); ++j) @@ -842,7 +850,6 @@ void cairo_renderer_base::process(building_symbolizer const& sym, } geom.rewind(0); - for (unsigned j = 0; j < geom.num_points(); ++j) { double x, y; diff --git a/src/deepcopy.cpp b/src/deepcopy.cpp new file mode 100644 index 000000000..0087e030d --- /dev/null +++ b/src/deepcopy.cpp @@ -0,0 +1,127 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2011 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ + +//$Id$ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// boost +#include +#include + + +namespace mapnik { namespace util { + +// poor man's deepcopy implementation + +void deepcopy(Map const& map_in, Map & map_out) +{ +// * width_(rhs.width_), +// * height_(rhs.height_), +// * srs_(rhs.srs_), +// * buffer_size_(rhs.buffer_size_), +// * background_(rhs.background_), +// * background_image_(rhs.background_image_), +// * styles_(rhs.styles_), +// metawriters_(rhs.metawriters_), +// fontsets_(rhs.fontsets_), +// * layers_(rhs.layers_), +// aspectFixMode_(rhs.aspectFixMode_), +// current_extent_(rhs.current_extent_), +// * maximum_extent_(rhs.maximum_extent_), +// * base_path_(rhs.base_path_), +// extra_attr_(rhs.extra_attr_), +// extra_params_(rhs.extra_params_) + + // width, height + map_out.resize(map_in.width(), map_in.height()); + // srs + map_out.set_srs(map_in.srs()); + // buffer_size + map_out.set_buffer_size(map_in.buffer_size()); + // background + boost::optional background = map_in.background(); + if (background) + { + map_out.set_background(*background); + } + // background_image + boost::optional background_image = map_in.background_image(); + if (background_image) + { + map_out.set_background_image(*background_image); + } + // maximum extent + boost::optional > max_extent = map_in.maximum_extent(); + if (max_extent) + { + map_out.set_maximum_extent(*max_extent); + } + // base_path + map_out.set_base_path(map_in.base_path()); + + // fontsets + typedef std::map fontsets; + BOOST_FOREACH ( fontsets::value_type const& kv,map_in.fontsets()) + { + map_out.insert_fontset(kv.first,kv.second); + } + + BOOST_FOREACH ( layer const& lyr_in, map_in.layers()) + { + layer lyr_out(lyr_in); + datasource_ptr ds_in = lyr_in.datasource(); + if (ds_in) + { + parameters p(ds_in->params()); + + // TODO : re-use datasource extent if already set. + datasource_ptr ds_out = datasource_cache::create(p); + if (ds_out) + { + lyr_out.set_datasource(ds_out); + } + } + map_out.addLayer(lyr_out); + } + typedef std::map style_cont; + typedef style_cont::value_type value_type; + + style_cont const& styles = map_in.styles(); + BOOST_FOREACH ( value_type const& kv, styles ) + { + feature_type_style const& style_in = kv.second; + feature_type_style style_out(style_in,true); // deep copy + map_out.insert_style(kv.first, style_out); + } + +} + +}} diff --git a/src/feature_style_processor.cpp b/src/feature_style_processor.cpp index ee9581288..ed173a1bd 100644 --- a/src/feature_style_processor.cpp +++ b/src/feature_style_processor.cpp @@ -25,13 +25,10 @@ #include #include #include -#include #include #include #include -#include #include -#include #include #include @@ -309,65 +306,23 @@ void feature_style_processor::apply_to_layer(layer const& lay, Proces } } - // push all property names - BOOST_FOREACH(std::string const& name, names) + // Don't even try to do more work if there are no active styles. + if (active_styles.size() > 0) { - q.add_property_name(name); - } - - memory_datasource cache; - bool cache_features = lay.cache_features() && num_styles>1?true:false; - bool first = true; - - #if defined(RENDERING_STATS) - int style_index = 0; - if (!active_styles.size() > 0) { - layer_timer.discard(); - } - #endif - BOOST_FOREACH (feature_type_style * style, active_styles) - { - #if defined(RENDERING_STATS) - std::string s_name = style_names[style_index]; - std::ostringstream s1; - s1 << "rendering style #" << style_index+1 - << " for layer: '" << lay.name() << "' and style '" << s_name << "'"; - mapnik::progress_timer style_timer(std::clog, s1.str()); - if (!num_styles>1) - style_timer.discard(); - style_index++; - #endif - - std::vector if_rules; - std::vector else_rules; - std::vector also_rules; - - std::vector const& rules=style->get_rules(); - - #if defined(RENDERING_STATS) - int feature_count = 0; - int feature_processed_count = 0; - #endif - - BOOST_FOREACH(rule const& r, rules) + // push all property names + BOOST_FOREACH(std::string const& name, names) { - if (r.active(scale_denom)) - { - if (r.has_else_filter()) - { - else_rules.push_back(const_cast(&r)); - } - else if (r.has_also_filter()) - { - also_rules.push_back(const_cast(&r)); - } - else - { - if_rules.push_back(const_cast(&r)); - } + q.add_property_name(name); + } - if ( (ds->type() == datasource::Raster) && - (ds->params().get("filter_factor",0.0) == 0.0) ) + // Update filter_factor for all enabled raster layers. + BOOST_FOREACH (feature_type_style * style, active_styles) + { + BOOST_FOREACH(rule const& r, style->get_rules()) + { + if (r.active(scale_denom) && + ds->type() == datasource::Raster && + ds->params().get("filter_factor",0.0) == 0.0) { rule::symbolizers const& symbols = r.get_symbolizers(); rule::symbolizers::const_iterator symIter = symbols.begin(); @@ -383,163 +338,235 @@ void feature_style_processor::apply_to_layer(layer const& lay, Proces } } - // process features - featureset_ptr fs; - if (first) + // Also query the group by attribute + std::string group_by = lay.group_by(); + if (group_by != "") { - if (cache_features) - first = false; - fs = ds->features(q); - } - else - { - fs = cache.features(q); + q.add_property_name(group_by); } - if (fs) + bool cache_features = lay.cache_features() && active_styles.size() > 1; + + // Render incrementally when the column that we group by + // changes value. + if (group_by != "") { - feature_ptr feature; - while ((feature = fs->next())) - { + featureset_ptr features = ds->features(q); + if (features) { + // Cache all features into the memory_datasource before rendering. + memory_datasource cache; + feature_ptr feature, prev; - #if defined(RENDERING_STATS) - feature_count++; - bool feat_processed = false; - #endif + while ((feature = features->next())) + { + if (prev && prev->props()[group_by] != feature->props()[group_by]) + { + // We're at a value boundary, so render what we have + // up to this point. + int i = 0; + BOOST_FOREACH (feature_type_style * style, active_styles) + { + render_style(lay, p, style, style_names[i++], + cache.features(q), prj_trans, scale_denom); + } + cache.clear(); + } + cache.push(feature); + prev = feature; + } - bool do_else=true; - bool do_also=false; - - if (cache_features) + int i = 0; + BOOST_FOREACH (feature_type_style * style, active_styles) + { + render_style(lay, p, style, style_names[i++], + cache.features(q), prj_trans, scale_denom); + } + } + } + else if (cache_features) + { + featureset_ptr features = ds->features(q); + if (features) { + // Cache all features into the memory_datasource before rendering. + memory_datasource cache; + feature_ptr feature; + while ((feature = features->next())) { cache.push(feature); } - BOOST_FOREACH(rule * r, if_rules ) + int i = 0; + BOOST_FOREACH (feature_type_style * style, active_styles) { - expression_ptr const& expr=r->get_filter(); - value_type result = boost::apply_visitor(evaluate(*feature),*expr); - if (result.to_bool()) - { - #if defined(RENDERING_STATS) - feat_processed = true; - #endif - - p.painted(true); - - do_else=false; - do_also=true; - rule::symbolizers const& symbols = r->get_symbolizers(); - - // if the underlying renderer is not able to process the complete set of symbolizers, - // process one by one. -#if defined(SVG_RENDERER) - if(!p.process(symbols,*feature,prj_trans)) -#endif - { - - BOOST_FOREACH (symbolizer const& sym, symbols) - { - boost::apply_visitor(symbol_dispatch(p,*feature,prj_trans),sym); - } - } - if (style->get_filter_mode() == FILTER_FIRST) - { - // Stop iterating over rules and proceed with next feature. - break; - } - } + render_style(lay, p, style, style_names[i++], + cache.features(q), prj_trans, scale_denom); } - if (do_else) - { - BOOST_FOREACH( rule * r, else_rules ) - { - #if defined(RENDERING_STATS) - feat_processed = true; - #endif - - p.painted(true); - - rule::symbolizers const& symbols = r->get_symbolizers(); - // if the underlying renderer is not able to process the complete set of symbolizers, - // process one by one. -#if defined(SVG_RENDERER) - if(!p.process(symbols,*feature,prj_trans)) -#endif - { - BOOST_FOREACH (symbolizer const& sym, symbols) - { - boost::apply_visitor(symbol_dispatch(p,*feature,prj_trans),sym); - } - } - } - } - if (do_also) - { - BOOST_FOREACH( rule * r, also_rules ) - { - #if defined(RENDERING_STATS) - feat_processed = true; - #endif - - p.painted(true); - - rule::symbolizers const& symbols = r->get_symbolizers(); - // if the underlying renderer is not able to process the complete set of symbolizers, - // process one by one. -#if defined(SVG_RENDERER) - if(!p.process(symbols,*feature,prj_trans)) -#endif - { - BOOST_FOREACH (symbolizer const& sym, symbols) - { - boost::apply_visitor(symbol_dispatch(p,*feature,prj_trans),sym); - } - } - } - } - #if defined(RENDERING_STATS) - if (feat_processed) - feature_processed_count++; - #endif } - - #if defined(RENDERING_STATS) - style_timer.stop(); - - // done with style - std::ostringstream s; - if (feature_count > 0) { - double perc_processed = ((double)feature_processed_count/(double)feature_count)*100.0; - - s << "percent rendered: " << perc_processed << "% - " << feature_processed_count - << " rendered for " << feature_count << " queried for "; - s << std::setw(15 - (int)s.tellp()) << " layer '" << lay.name() << "' and style '" << s_name << "'\n"; - - } else { - s << "" << std::setw(15) << "- no features returned from query for layer '" << lay.name() << "' and style '" << s_name << "'\n"; + } + // We only have a single style and no grouping. + else + { + int i = 0; + BOOST_FOREACH (feature_type_style * style, active_styles) + { + featureset_ptr features = ds->features(q); + if (features) { + render_style(lay, p, style, style_names[i++], + features, prj_trans, scale_denom); + } } - std::clog << s.str(); - #endif - } - #if defined(RENDERING_STATS) - else { - style_timer.discard(); - layer_timer.discard(); - } - #endif - cache_features = false; } - + #if defined(RENDERING_STATS) layer_timer.stop(); #endif - p.end_layer_processing(lay); } + +template +void feature_style_processor::render_style( + layer const& lay, + Processor & p, + feature_type_style* style, + std::string const& style_name, + featureset_ptr features, + proj_transform const& prj_trans, + double scale_denom) +{ + #if defined(RENDERING_STATS) + std::ostringstream s1; + s1 << "rendering style for layer: '" << lay.name() + << "' and style '" << style_name << "'"; + mapnik::progress_timer style_timer(std::clog, s1.str()); + + int feature_processed_count = 0; + int feature_count = 0; + #endif + + feature_ptr feature; + while ((feature = features->next())) + { + #if defined(RENDERING_STATS) + feature_count++; + bool feat_processed = false; + #endif + + bool do_else = true; + bool do_also = false; + + BOOST_FOREACH(rule * r, style->get_if_rules(scale_denom) ) + { + expression_ptr const& expr=r->get_filter(); + value_type result = boost::apply_visitor(evaluate(*feature),*expr); + if (result.to_bool()) + { + #if defined(RENDERING_STATS) + feat_processed = true; + #endif + + p.painted(true); + + do_else=false; + do_also=true; + rule::symbolizers const& symbols = r->get_symbolizers(); + + // if the underlying renderer is not able to process the complete set of symbolizers, + // process one by one. +#if defined(SVG_RENDERER) + if(!p.process(symbols,*feature,prj_trans)) +#endif + { + + BOOST_FOREACH (symbolizer const& sym, symbols) + { + boost::apply_visitor(symbol_dispatch(p,*feature,prj_trans),sym); + } + } + if (style->get_filter_mode() == FILTER_FIRST) + { + // Stop iterating over rules and proceed with next feature. + break; + } + } + } + if (do_else) + { + BOOST_FOREACH( rule * r, style->get_else_rules(scale_denom) ) + { + #if defined(RENDERING_STATS) + feat_processed = true; + #endif + + p.painted(true); + + rule::symbolizers const& symbols = r->get_symbolizers(); + // if the underlying renderer is not able to process the complete set of symbolizers, + // process one by one. +#if defined(SVG_RENDERER) + if(!p.process(symbols,*feature,prj_trans)) +#endif + { + BOOST_FOREACH (symbolizer const& sym, symbols) + { + boost::apply_visitor(symbol_dispatch(p,*feature,prj_trans),sym); + } + } + } + } + if (do_also) + { + BOOST_FOREACH( rule * r, style->get_also_rules(scale_denom) ) + { + #if defined(RENDERING_STATS) + feat_processed = true; + #endif + + p.painted(true); + + rule::symbolizers const& symbols = r->get_symbolizers(); + // if the underlying renderer is not able to process the complete set of symbolizers, + // process one by one. +#if defined(SVG_RENDERER) + if(!p.process(symbols,*feature,prj_trans)) +#endif + { + BOOST_FOREACH (symbolizer const& sym, symbols) + { + boost::apply_visitor(symbol_dispatch(p,*feature,prj_trans),sym); + } + } + } + } + #if defined(RENDERING_STATS) + if (feat_processed) + feature_processed_count++; + #endif + } + + #if defined(RENDERING_STATS) + style_timer.stop(); + + // done with style + std::ostringstream s; + if (feature_count > 0) { + double perc_processed = ((double)feature_processed_count/(double)feature_count)*100.0; + + s << "percent rendered: " << perc_processed << "% - " << feature_processed_count + << " rendered for " << feature_count << " queried for "; + s << std::setw(15 - (int)s.tellp()) << " layer '" << lay.name() << "' and style '" << s_name << "'\n"; + + } else { + s << "" << std::setw(15) << "- no features returned from query for layer '" << lay.name() << "' and style '" << s_name << "'\n"; + } + std::clog << s.str(); + style_timer.discard(); + #endif +} + + #if defined(HAVE_CAIRO) template class feature_style_processor >; template class feature_style_processor >; diff --git a/src/feature_type_style.cpp b/src/feature_type_style.cpp index e0a7a8336..6dc0fe86b 100644 --- a/src/feature_type_style.cpp +++ b/src/feature_type_style.cpp @@ -35,10 +35,12 @@ IMPLEMENT_ENUM( filter_mode_e, filter_mode_strings ) feature_type_style::feature_type_style() - : filter_mode_(FILTER_ALL) {} + : filter_mode_(FILTER_ALL), + scale_denom_validity_(-1) {} feature_type_style::feature_type_style(feature_type_style const& rhs, bool deep_copy) - : filter_mode_(rhs.filter_mode_) + : filter_mode_(rhs.filter_mode_), + scale_denom_validity_(-1) { if (!deep_copy) { rules_ = rhs.rules_; @@ -55,12 +57,14 @@ feature_type_style& feature_type_style::operator=(feature_type_style const& rhs) { if (this == &rhs) return *this; rules_=rhs.rules_; + scale_denom_validity_ = -1; return *this; } void feature_type_style::add_rule(rule const& rule) { rules_.push_back(rule); + scale_denom_validity_ = -1; } rules const& feature_type_style::get_rules() const @@ -83,4 +87,60 @@ filter_mode_e feature_type_style::get_filter_mode() const return filter_mode_; } + +void feature_type_style::update_rule_cache(double scale_denom) +{ + if_rules_.clear(); + else_rules_.clear(); + also_rules_.clear(); + + BOOST_FOREACH(rule const& r, rules_) + { + if (r.active(scale_denom)) + { + if (r.has_else_filter()) + { + else_rules_.push_back(const_cast(&r)); + } + else if (r.has_also_filter()) + { + also_rules_.push_back(const_cast(&r)); + } + else + { + if_rules_.push_back(const_cast(&r)); + } + } + } + + scale_denom_validity_ = scale_denom; +} + +rule_ptrs const& feature_type_style::get_if_rules(double scale_denom) +{ + if (scale_denom_validity_ != scale_denom) + { + update_rule_cache(scale_denom); + } + return if_rules_; +} + +rule_ptrs const& feature_type_style::get_else_rules(double scale_denom) +{ + if (scale_denom_validity_ != scale_denom) + { + update_rule_cache(scale_denom); + } + return else_rules_; +} + +rule_ptrs const& feature_type_style::get_also_rules(double scale_denom) +{ + if (scale_denom_validity_ != scale_denom) + { + update_rule_cache(scale_denom); + } + return also_rules_; +} + } diff --git a/src/font_engine_freetype.cpp b/src/font_engine_freetype.cpp index 769abcbe7..188aaa59d 100644 --- a/src/font_engine_freetype.cpp +++ b/src/font_engine_freetype.cpp @@ -78,29 +78,36 @@ bool freetype_engine::register_font(std::string const& file_name) throw std::runtime_error("Failed to initialize FreeType2 library"); } - FT_Face face; - error = FT_New_Face (library,file_name.c_str(),0,&face); - if (error) - { - FT_Done_FreeType(library); - return false; - } - // some fonts can lack names, skip them - // http://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_FaceRec - if (face->family_name && face->style_name) { - std::string name = std::string(face->family_name) + " " + std::string(face->style_name); - name2file_.insert(std::make_pair(name,file_name)); - FT_Done_Face(face); - FT_Done_FreeType(library); - return true; - } else { - FT_Done_Face(face); - FT_Done_FreeType(library); - std::ostringstream s; - s << "Error: unable to load invalid font file which lacks identifiable family and style name: '" - << file_name << "'"; - throw std::runtime_error(s.str()); + FT_Face face = 0; + // some font files have multiple fonts in a file + // the count is in the 'root' face library[0] + // see the FT_FaceRec in freetype.h + for ( int i = 0; face == 0 || i < face->num_faces; i++ ) { + // if face is null then this is the first face + error = FT_New_Face (library,file_name.c_str(),i,&face); + if (error) + { + FT_Done_FreeType(library); + return false; + } + // some fonts can lack names, skip them + // http://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_FaceRec + if (face->family_name && face->style_name) { + std::string name = std::string(face->family_name) + " " + std::string(face->style_name); + name2file_.insert(std::make_pair(name, std::make_pair(i,file_name))); + FT_Done_Face(face); + //FT_Done_FreeType(library); + //return true; + } else { + FT_Done_Face(face); + FT_Done_FreeType(library); + std::ostringstream s; + s << "Error: unable to load invalid font file which lacks identifiable family and style name: '" + << file_name << "'"; + throw std::runtime_error(s.str()); + } } + FT_Done_FreeType(library); return true; } @@ -141,7 +148,7 @@ bool freetype_engine::register_fonts(std::string const& dir, bool recurse) std::vector freetype_engine::face_names () { std::vector names; - std::map::const_iterator itr; + std::map >::const_iterator itr; for (itr = name2file_.begin();itr!=name2file_.end();++itr) { names.push_back(itr->first); @@ -149,7 +156,7 @@ std::vector freetype_engine::face_names () return names; } -std::map const& freetype_engine::get_mapping() +std::map > const& freetype_engine::get_mapping() { return name2file_; } @@ -157,15 +164,17 @@ std::map const& freetype_engine::get_mapping() face_ptr freetype_engine::create_face(std::string const& family_name) { - std::map::iterator itr; + std::map >::iterator itr; itr = name2file_.find(family_name); if (itr != name2file_.end()) { FT_Face face; - FT_Error error = FT_New_Face (library_,itr->second.c_str(),0,&face); - + FT_Error error = FT_New_Face (library_, + itr->second.second.c_str(), + itr->second.first, + &face); if (!error) - { + { return face_ptr (new font_face(face)); } } @@ -283,5 +292,5 @@ void font_face_set::get_string_info(string_info & info) #ifdef MAPNIK_THREADSAFE boost::mutex freetype_engine::mutex_; #endif -std::map freetype_engine::name2file_; +std::map > freetype_engine::name2file_; } diff --git a/src/grid/process_building_symbolizer.cpp b/src/grid/process_building_symbolizer.cpp index 27c156a27..dcbb3665e 100644 --- a/src/grid/process_building_symbolizer.cpp +++ b/src/grid/process_building_symbolizer.cpp @@ -28,6 +28,7 @@ #include #include #include +#include // boost #include @@ -59,7 +60,13 @@ void grid_renderer::process(building_symbolizer const& sym, ras_ptr->reset(); - double height = sym.height() * scale_factor_; + double height = 0.0; + expression_ptr height_expr = sym.height(); + if (height_expr) + { + value_type result = boost::apply_visitor(evaluate(feature), *height_expr); + height = result.to_double() * scale_factor_; + } for (unsigned i=0;i::max()), @@ -46,12 +44,11 @@ layer::layer(std::string const& name, std::string const& srs) queryable_(false), clear_label_cache_(false), cache_features_(false), + group_by_(""), ds_() {} layer::layer(const layer& rhs) : name_(rhs.name_), - title_(rhs.title_), - abstract_(rhs.abstract_), srs_(rhs.srs_), minZoom_(rhs.minZoom_), maxZoom_(rhs.maxZoom_), @@ -59,6 +56,7 @@ layer::layer(const layer& rhs) queryable_(rhs.queryable_), clear_label_cache_(rhs.clear_label_cache_), cache_features_(rhs.cache_features_), + group_by_(rhs.group_by_), styles_(rhs.styles_), ds_(rhs.ds_) {} @@ -77,8 +75,6 @@ bool layer::operator==(layer const& other) const void layer::swap(const layer& rhs) { name_=rhs.name_; - title_=rhs.title_; - abstract_=rhs.abstract_; srs_ = rhs.srs_; minZoom_=rhs.minZoom_; maxZoom_=rhs.maxZoom_; @@ -86,6 +82,7 @@ void layer::swap(const layer& rhs) queryable_=rhs.queryable_; clear_label_cache_ = rhs.clear_label_cache_; cache_features_ = rhs.cache_features_; + group_by_ = rhs.group_by_; styles_=rhs.styles_; ds_=rhs.ds_; } @@ -102,26 +99,6 @@ std::string const& layer::name() const return name_; } -void layer::set_title( std::string const& title) -{ - title_ = title; -} - -std::string const& layer::title() const -{ - return title_; -} - -void layer::set_abstract( std::string const& abstract) -{ - abstract_ = abstract; -} - -std::string const& layer::abstract() const -{ - return abstract_; -} - void layer::set_srs(std::string const& srs) { srs_ = srs; @@ -228,4 +205,14 @@ bool layer::cache_features() const return cache_features_; } +void layer::set_group_by(std::string column) +{ + group_by_ = column; +} + +std::string layer::group_by() const +{ + return group_by_; +} + } diff --git a/src/load_map.cpp b/src/load_map.cpp index 49913ef2b..d7665000b 100644 --- a/src/load_map.cpp +++ b/src/load_map.cpp @@ -560,14 +560,19 @@ void map_parser::parse_font(font_set & fset, ptree const & f) { ensure_attrs(f, "Font", "face-name"); - std::string face_name = get_attr(f, "face-name", std::string()); - - if ( strict_ ) + optional face_name = get_opt_attr(f, "face-name"); + if (face_name) { - ensure_font_face( face_name ); + if ( strict_ ) + { + ensure_font_face(*face_name); + } + fset.add_face_name(*face_name); + } + else + { + throw config_error(std::string("Must have 'face-name' set")); } - - fset.add_face_name(face_name); } void map_parser::parse_layer( Map & map, ptree const & lay ) @@ -577,13 +582,12 @@ void map_parser::parse_layer( Map & map, ptree const & lay ) s << "name," << "srs," << "status," - << "title," - << "abstract," << "minzoom," << "maxzoom," << "queryable," << "clear-label-cache," - << "cache-features"; + << "cache-features," + << "group-by"; ensure_attrs(lay, "Layer", s.str()); try { @@ -599,19 +603,7 @@ void map_parser::parse_layer( Map & map, ptree const & lay ) { lyr.setActive( * status ); } - - optional title = get_opt_attr(lay, "title"); - if (title) - { - lyr.set_title( * title ); - } - - optional abstract = get_opt_attr(lay, "abstract"); - if (abstract) - { - lyr.set_abstract( * abstract ); - } - + optional minZoom = get_opt_attr(lay, "minzoom"); if (minZoom) { @@ -644,6 +636,12 @@ void map_parser::parse_layer( Map & map, ptree const & lay ) lyr.set_cache_features( * cache_features ); } + optional group_by = + get_opt_attr(lay, "group-by"); + if (group_by) + { + lyr.set_group_by( * group_by ); + } ptree::const_iterator itr2 = lay.begin(); ptree::const_iterator end2 = lay.end(); @@ -758,14 +756,12 @@ void map_parser::parse_layer( Map & map, ptree const & lay ) void map_parser::parse_rule( feature_type_style & style, ptree const & r ) { - ensure_attrs(r, "Rule", "name,title"); + ensure_attrs(r, "Rule", "name"); std::string name; try { name = get_attr( r, "name", std::string()); - std::string title = get_attr( r, "title", std::string()); - - rule rule(name,title); + rule rule(name); optional filter_expr = get_opt_child( r, "Filter"); @@ -1915,9 +1911,8 @@ void map_parser::parse_building_symbolizer( rule & rule, ptree const & sym ) optional opacity = get_opt_attr(sym, "fill-opacity"); if (opacity) building_sym.set_opacity(*opacity); // height - // TODO - expression - optional height = get_opt_attr(sym, "height"); - if (height) building_sym.set_height(*height); + optional height = get_opt_attr(sym, "height"); + if (height) building_sym.set_height(parse_expression(*height, "utf8")); parse_metawriter_in_symbolizer(building_sym, sym); rule.append(building_sym); diff --git a/src/map.cpp b/src/map.cpp index ec974fb49..e421998b8 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -87,6 +87,7 @@ Map::Map(const Map& rhs) background_image_(rhs.background_image_), styles_(rhs.styles_), metawriters_(rhs.metawriters_), + fontsets_(rhs.fontsets_), layers_(rhs.layers_), aspectFixMode_(rhs.aspectFixMode_), current_extent_(rhs.current_extent_), @@ -106,6 +107,7 @@ Map& Map::operator=(const Map& rhs) background_image_=rhs.background_image_; styles_=rhs.styles_; metawriters_ = rhs.metawriters_; + fontsets_ = rhs.fontsets_; layers_=rhs.layers_; aspectFixMode_=rhs.aspectFixMode_; maximum_extent_=rhs.maximum_extent_; @@ -202,14 +204,14 @@ bool Map::insert_fontset(std::string const& name, font_set const& fontset) { return fontsets_.insert(make_pair(name, fontset)).second; } - -font_set const& Map::find_fontset(std::string const& name) const + +boost::optional Map::find_fontset(std::string const& name) const { std::map::const_iterator itr = fontsets_.find(name); - if (itr!=fontsets_.end()) - return itr->second; - static font_set default_fontset; - return default_fontset; + if (itr != fontsets_.end()) + return boost::optional(itr->second); + else + return boost::optional() ; } std::map const& Map::fontsets() const diff --git a/src/memory_datasource.cpp b/src/memory_datasource.cpp index bc60255cd..9771e30a9 100644 --- a/src/memory_datasource.cpp +++ b/src/memory_datasource.cpp @@ -107,6 +107,11 @@ size_t memory_datasource::size() const return features_.size(); } +void memory_datasource::clear() +{ + features_.clear(); +} + // point_datasource void point_datasource::add_point(double x, double y, const char* key, const char* value) diff --git a/src/placement_finder.cpp b/src/placement_finder.cpp index b0dafd56b..c965d03cf 100644 --- a/src/placement_finder.cpp +++ b/src/placement_finder.cpp @@ -293,7 +293,7 @@ void placement_finder::find_point_placement(placement & p, // wrap text at first wrap_char after (default) the wrap width or immediately before the current word if ((c == '\n') || (line_width > 0 && (((line_width - character_spacing) > wrap_at && !p.wrap_before) || - ((line_width + word_width - character_spacing) > wrap_at && p.wrap_before)) )) + ((line_width + word_width - character_spacing) > wrap_at && p.wrap_before)) )) { // Remove width of breaking space character since it is not rendered and the character_spacing for the last character on the line line_width -= (last_wrap_char_width + character_spacing); @@ -381,12 +381,12 @@ void placement_finder::find_point_placement(placement & p, x = -(line_width / 2.0); if (p.info.get_rtl()==false) { - y = (0.5 * (string_height + (line_spacing * (total_lines-1)))) - max_character_height; - } - else - { - y = -(0.5 * (string_height + (line_spacing * (total_lines-1)))) + max_character_height; - } + y = (0.5 * (string_height + (line_spacing * (total_lines-1)))) - max_character_height; + } + else + { + y = -(0.5 * (string_height + (line_spacing * (total_lines-1)))) + max_character_height; + } // if needed, adjust for desired justification (J_MIDDLE is the default) if( po->jalign == J_LEFT ) @@ -411,14 +411,14 @@ void placement_finder::find_point_placement(placement & p, index_to_wrap_at = line_breaks[++line_number]; line_width = line_widths[line_number]; - if (p.info.get_rtl()==false) - { - y -= (max_character_height + line_spacing); // move position down to line start - } - else - { - y += (max_character_height + line_spacing); // move position up to line start - } + if (p.info.get_rtl()==false) + { + y -= (max_character_height + line_spacing); // move position down to line start + } + else + { + y += (max_character_height + line_spacing); // move position up to line start + } // reset to begining of line position x = ((po->jalign == J_LEFT)? -(string_width / 2.0): ((po->jalign == J_RIGHT)? ((string_width /2.0) - line_width): -(line_width / 2.0))); @@ -467,9 +467,9 @@ void placement_finder::find_point_placement(placement & p, if (p.minimum_padding > 0) { box2d epad(e.minx()-p.minimum_padding, - e.miny()-p.minimum_padding, - e.maxx()+p.minimum_padding, - e.maxy()+p.minimum_padding); + e.miny()-p.minimum_padding, + e.maxx()+p.minimum_padding, + e.maxy()+p.minimum_padding); if (!dimensions_.contains(epad)) { return; @@ -485,18 +485,18 @@ void placement_finder::find_point_placement(placement & p, // check the placement of any additional envelopes if (!p.allow_overlap && !p.additional_boxes.empty()) { - BOOST_FOREACH(box2d box, p.additional_boxes) - { - box2d pt(box.minx() + current_placement->starting_x, - box.miny() + current_placement->starting_y, - box.maxx() + current_placement->starting_x, - box.maxy() + current_placement->starting_y); + BOOST_FOREACH(box2d box, p.additional_boxes) + { + box2d pt(box.minx() + current_placement->starting_x, + box.miny() + current_placement->starting_y, + box.maxx() + current_placement->starting_x, + box.maxy() + current_placement->starting_y); - // abort the whole placement if the additional envelopes can't be placed. - if (!detector_.has_point_placement(pt, p.minimum_distance)) return; + // abort the whole placement if the additional envelopes can't be placed. + if (!detector_.has_point_placement(pt, p.minimum_distance)) return; - c_envelopes.push(pt); - } + c_envelopes.push(pt); + } } // since there was no early exit, add the character envelopes to the placements' envelopes diff --git a/src/raster_colorizer.cpp b/src/raster_colorizer.cpp index 95aec3cb7..554592246 100644 --- a/src/raster_colorizer.cpp +++ b/src/raster_colorizer.cpp @@ -138,7 +138,7 @@ void raster_colorizer::colorize(raster_ptr const& raster,const std::map(fraction * (end - start) + start); + return static_cast(fraction * ((float)end - (float)start) + start); } color raster_colorizer::get_color(float value) const { diff --git a/src/save_map.cpp b/src/save_map.cpp index f7616f3e2..a26fd3d93 100644 --- a/src/save_map.cpp +++ b/src/save_map.cpp @@ -241,10 +241,9 @@ public: { set_attr( sym_node, "fill-opacity", sym.get_opacity() ); } - if ( sym.height() != dfl.height() || explicit_defaults_ ) - { - set_attr( sym_node, "height", sym.height() ); - } + + set_attr( sym_node, "height", to_expression_string(*sym.height()) ); + add_metawriter_attributes(sym_node, sym); } @@ -647,11 +646,7 @@ void serialize_rule( ptree & style_node, const rule & r, bool explicit_defaults) { set_attr(rule_node, "name", r.get_name()); } - if ( r.get_title() != dfl.get_title() ) - { - set_attr(rule_node, "title", r.get_title()); - } - + if ( r.has_else_filter() ) { rule_node.push_back( ptree::value_type( @@ -815,21 +810,12 @@ void serialize_layer( ptree & map_node, const layer & layer, bool explicit_defau { ptree & layer_node = map_node.push_back( ptree::value_type("Layer", ptree()))->second; + if ( layer.name() != "" ) { set_attr( layer_node, "name", layer.name() ); } - - if ( layer.abstract() != "" ) - { - set_attr( layer_node, "abstract", layer.abstract() ); - } - - if ( layer.title() != "" ) - { - set_attr( layer_node, "title", layer.title() ); - } - + if ( layer.srs() != "" ) { set_attr( layer_node, "srs", layer.srs() ); @@ -865,6 +851,11 @@ void serialize_layer( ptree & map_node, const layer & layer, bool explicit_defau set_attr/**/( layer_node, "cache-features", layer.cache_features() ); } + if ( layer.group_by() != "" || explicit_defaults ) + { + set_attr( layer_node, "group-by", layer.group_by() ); + } + std::vector const& style_names = layer.styles(); for (unsigned i = 0; i < style_names.size(); ++i) { diff --git a/src/wkb.cpp b/src/wkb.cpp index f704971b7..158311cc4 100644 --- a/src/wkb.cpp +++ b/src/wkb.cpp @@ -114,16 +114,13 @@ public: needSwap_ = byteOrder_ ? wkbNDR : wkbXDR; #endif } - - ~wkb_reader() {} - - void read_multi(boost::ptr_vector & paths) + + void read(boost::ptr_vector & paths) { int type = read_integer(); #ifdef MAPNIK_DEBUG_WKB - std::clog << "wkb_reader: read_multi " - << wkb_geometry_type_string(type) << " " << type << std::endl; + std::clog << "wkb_reader: read " << wkb_geometry_type_string(type) << " " << type << std::endl; #endif switch (type) @@ -174,63 +171,6 @@ public: break; } } - - void read(boost::ptr_vector & paths) - { - int type = read_integer(); - -#ifdef MAPNIK_DEBUG_WKB - std::clog << "wkb_reader: read " << wkb_geometry_type_string(type) << " " << type << std::endl; -#endif - - switch (type) - { - case wkbPoint: - read_point(paths); - break; - case wkbLineString: - read_linestring(paths); - break; - case wkbPolygon: - read_polygon(paths); - break; - case wkbMultiPoint: - read_multipoint_2(paths); - break; - case wkbMultiLineString: - read_multilinestring_2(paths); - break; - case wkbMultiPolygon: - read_multipolygon_2(paths); - break; - case wkbGeometryCollection: - read_collection_2(paths); - break; - case wkbPointZ: - read_point_xyz(paths); - break; - case wkbLineStringZ: - read_linestring_xyz(paths); - break; - case wkbPolygonZ: - read_polygon_xyz(paths); - break; - case wkbMultiPointZ: - read_multipoint_xyz_2(paths); - break; - case wkbMultiLineStringZ: - read_multilinestring_xyz_2(paths); - break; - case wkbMultiPolygonZ: - read_multipolygon_xyz_2(paths); - break; - case wkbGeometryCollectionZ: - read_collection_2(paths); - break; - default: - break; - } - } private: @@ -329,21 +269,7 @@ private: read_point(paths); } } - - void read_multipoint_2(boost::ptr_vector & paths) - { - geometry_type* pt = new geometry_type(MultiPoint); - int num_points = read_integer(); - for (int i = 0; i < num_points; ++i) - { - pos_ += 5; - double x = read_double(); - double y = read_double(); - pt->move_to(x, y); - } - paths.push_back(pt); - } - + void read_point_xyz(boost::ptr_vector & paths) { geometry_type* pt = new geometry_type(Point); @@ -364,22 +290,6 @@ private: } } - void read_multipoint_xyz_2(boost::ptr_vector & paths) - { - geometry_type* pt = new geometry_type(MultiPoint); - int num_points = read_integer(); - for (int i = 0; i < num_points; ++i) - { - pos_ += 5; - double x = read_double(); - double y = read_double(); - pos_ += 8; // double z = read_double(); - pt->move_to(x, y); - } - paths.push_back(pt); - } - - void read_linestring(boost::ptr_vector & paths) { geometry_type* line = new geometry_type(LineString); @@ -404,29 +314,7 @@ private: read_linestring(paths); } } - - void read_multilinestring_2(boost::ptr_vector & paths) - { - geometry_type* line = new geometry_type(MultiLineString); - int num_lines = read_integer(); - 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); - } - + void read_linestring_xyz(boost::ptr_vector & paths) { geometry_type* line = new geometry_type(LineString); @@ -452,29 +340,7 @@ private: } } - void read_multilinestring_xyz_2(boost::ptr_vector & paths) - { - geometry_type* line = new geometry_type(MultiLineString); - int num_lines = read_integer(); - 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_xyz(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); - } - - + void read_polygon(boost::ptr_vector & paths) { geometry_type* poly = new geometry_type(Polygon); @@ -506,33 +372,6 @@ private: } } - void read_multipolygon_2(boost::ptr_vector & paths) - { - geometry_type* poly = new geometry_type(MultiPolygon); - int num_polys = read_integer(); - unsigned capacity = 0; - for (int i = 0; i < num_polys; ++i) - { - pos_ += 5; - int num_rings = read_integer(); - for (int r = 0; r < num_rings; ++r) - { - 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); - } - poly->line_to(ar[0].x, ar[0].y); - } - } - paths.push_back(poly); - } - void read_polygon_xyz(boost::ptr_vector & paths) { geometry_type* poly = new geometry_type(Polygon); @@ -564,34 +403,6 @@ private: } } - void read_multipolygon_xyz_2(boost::ptr_vector & paths) - { - geometry_type* poly = new geometry_type(MultiPolygon); - int num_polys = read_integer(); - unsigned capacity = 0; - for (int i = 0; i < num_polys; ++i) - { - pos_ += 5; - int num_rings = read_integer(); - for (int r = 0; r < num_rings; ++r) - { - int num_points = read_integer(); - capacity += num_points; - CoordinateArray ar(num_points); - read_coords_xyz(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); - } - } - paths.push_back(poly); - } - - void read_collection(boost::ptr_vector & paths) { int num_geometries = read_integer(); @@ -602,16 +413,6 @@ private: } } - void read_collection_2(boost::ptr_vector & paths) - { - int num_geometries = read_integer(); - for (int i = 0; i < num_geometries; ++i) - { - pos_ += 1; // skip byte order - read_multi(paths); - } - } - #ifdef MAPNIK_DEBUG_WKB std::string wkb_geometry_type_string(int type) { @@ -645,17 +446,10 @@ private: void geometry_utils::from_wkb (boost::ptr_vector& paths, const char* wkb, unsigned size, - bool multiple_geometries, wkbFormat format) { wkb_reader reader(wkb, size, format); - if (multiple_geometries) - { - return reader.read_multi(paths); - } - else - { - return reader.read(paths); - } + return reader.read(paths); } + } diff --git a/tests/data/broken_maps/missing_fontset.xml b/tests/data/broken_maps/missing_fontset.xml new file mode 100644 index 000000000..f36337d77 --- /dev/null +++ b/tests/data/broken_maps/missing_fontset.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/tests/data/csv/leading_zeros.csv b/tests/data/csv/leading_zeros.csv new file mode 100644 index 000000000..f0d8615dc --- /dev/null +++ b/tests/data/csv/leading_zeros.csv @@ -0,0 +1,4 @@ +x,y,fips +0,0,001 +0,0,003 +0,0,005 diff --git a/tests/data/good_maps/fontset.xml b/tests/data/good_maps/fontset.xml new file mode 100644 index 000000000..80ab2cd60 --- /dev/null +++ b/tests/data/good_maps/fontset.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/tests/data/good_maps/line_symbolizer2.xml b/tests/data/good_maps/line_symbolizer2.xml index 1f0430aa5..7133720fa 100644 --- a/tests/data/good_maps/line_symbolizer2.xml +++ b/tests/data/good_maps/line_symbolizer2.xml @@ -3,7 +3,6 @@ sqlite ../sqlite/qgis_spatiallite.sqlite - true - - - - world_borders_style1 - - ogr - ../sqlite/world.sqlite - world_merc - - - - + + world_borders_style1 world_borders_style2 sqlite diff --git a/tests/data/good_maps/text_rotation.xml b/tests/data/good_maps/text_rotation.xml index df1d8202f..f37dbf5af 100644 --- a/tests/data/good_maps/text_rotation.xml +++ b/tests/data/good_maps/text_rotation.xml @@ -1,31 +1,31 @@