diff --git a/.gitignore b/.gitignore index 53b816877..1da77f7c9 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ *.a *.dylib plugins/input/*.input +plugins/input/templates/*.input demo/c++/rundemo bindings/python/mapnik/paths.py config.cache diff --git a/CHANGELOG b/CHANGELOG index 49aa4e399..caa88a4ad 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -14,6 +14,8 @@ For a complete change history, see the SVN log. Mapnik 2.1.0 ------------ +- Removed PointDatasource - use more robust MemoryDatasource instead (#1032) + - 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) diff --git a/bindings/python/mapnik/__init__.py b/bindings/python/mapnik/__init__.py index 458f85029..f646133cb 100644 --- a/bindings/python/mapnik/__init__.py +++ b/bindings/python/mapnik/__init__.py @@ -247,44 +247,6 @@ class _Datasource(Datasource,_injector): query.add_property_name(fld) return self.features(query) -class _DeprecatedFeatureProperties(object): - - def __init__(self, feature): - self._feature = feature - - def __getitem__(self, name): - warnings.warn("indexing feature.properties is deprecated, index the " - "feature object itself for the same effect", DeprecationWarning, 2) - return self._feature[name] - - def __iter__(self): - warnings.warn("iterating feature.properties is deprecated, iterate the " - "feature object itself for the same effect", DeprecationWarning, 2) - return iter(self._feature) - -class _Feature(Feature, _injector): - """ - A Feature. - - TODO: docs - """ - @property - def properties(self): - return _DeprecatedFeatureProperties(self) - - @property - def attributes(self): - #XXX Returns a copy! changes to it won't affect feat.'s attrs. - # maybe deprecate? - return dict(self) - - def __init__(self, id, wkt=None, **properties): - Feature._c___init__(self, id) - if wkt is not None: - self.add_geometries_from_wkt(wkt) - for k, v in properties.iteritems(): - self[k] = v - class _Color(Color,_injector): def __repr__(self): return "Color(R=%d,G=%d,B=%d,A=%d)" % (self.r,self.g,self.b,self.a) @@ -663,7 +625,6 @@ __all__ = [ 'Path', 'Parameter', 'Parameters', - 'PointDatasource', 'PointSymbolizer', 'PolygonPatternSymbolizer', 'PolygonSymbolizer', diff --git a/bindings/python/mapnik_datasource.cpp b/bindings/python/mapnik_datasource.cpp index 7f9ce5d2f..d7b83040e 100644 --- a/bindings/python/mapnik_datasource.cpp +++ b/bindings/python/mapnik_datasource.cpp @@ -36,7 +36,6 @@ using mapnik::datasource; -using mapnik::point_datasource; using mapnik::memory_datasource; using mapnik::layer_descriptor; using mapnik::attribute_descriptor; @@ -178,11 +177,6 @@ void export_datasource() def("CreateDatasource",&create_datasource); - class_, boost::noncopyable>("PointDatasource", init<>()) - .def("add_point",&point_datasource::add_point) - ; - - class_, boost::noncopyable>("MemoryDatasource", init<>()) .def("add_feature",&memory_datasource::push, "Adds a Feature:\n" diff --git a/bindings/python/mapnik_feature.cpp b/bindings/python/mapnik_feature.cpp index 4bc392af4..fcf4f75ac 100644 --- a/bindings/python/mapnik_feature.cpp +++ b/bindings/python/mapnik_feature.cpp @@ -22,26 +22,35 @@ //$Id$ // boost + #include +//#include + #include #include #include +#include #include #include // mapnik #include +#include #include #include #include -mapnik::geometry_type & (mapnik::Feature::*get_geom1)(unsigned) = &mapnik::Feature::get_geometry; - namespace { using mapnik::Feature; using mapnik::geometry_utils; using mapnik::from_wkt; +using mapnik::context_type; +using mapnik::context_ptr; +using mapnik::feature_kv_iterator; + +mapnik::geometry_type const& (mapnik::Feature::*get_geometry_by_const_ref)(unsigned) const = &mapnik::Feature::get_geometry; +boost::ptr_vector const& (mapnik::Feature::*get_paths_by_const_ref)() const = &mapnik::Feature::paths; void feature_add_geometries_from_wkb(Feature &feature, std::string wkb) { @@ -54,152 +63,36 @@ void feature_add_geometries_from_wkt(Feature &feature, std::string wkt) if (!result) throw std::runtime_error("Failed to parse WKT"); } -} // end anonymous namespace +mapnik::value __getitem__(Feature const& feature, std::string const& name) +{ + return feature.get(name); +} -namespace boost { namespace python { +mapnik::value __getitem2__(Feature const& feature, std::size_t index) +{ + return feature.get(index); +} - // Forward declaration - template - class map_indexing_suite2; +void __setitem__(Feature & feature, std::string const& name, mapnik::value const& val) +{ + feature.put_new(name,val); +} - namespace detail +boost::python::dict attributes(Feature const& f) +{ + boost::python::dict attributes; + feature_kv_iterator itr = f.begin(); + feature_kv_iterator end = f.end(); + + for ( ;itr!=end; ++itr) { - template - class final_map_derived_policies - : public map_indexing_suite2 > {}; + attributes[boost::get<0>(*itr)] = boost::get<1>(*itr); } + + return attributes; +} - template > - class map_indexing_suite2 - : public indexing_suite< - Container - , DerivedPolicies - , NoProxy - , true - , typename Container::value_type::second_type - , typename Container::key_type - , typename Container::key_type - > - { - public: - - typedef typename Container::value_type value_type; - typedef typename Container::value_type::second_type data_type; - typedef typename Container::key_type key_type; - typedef typename Container::key_type index_type; - typedef typename Container::size_type size_type; - typedef typename Container::difference_type difference_type; - - template - static void - extension_def(Class& cl) - { - cl - .def("get", &get) - ; - } - - static data_type& - get_item(Container& container, index_type i_) - { - typename Container::iterator i = container.props().find(i_); - if (i == container.end()) - { - PyErr_SetString(PyExc_KeyError, i_.c_str()); - throw_error_already_set(); - } - // will be auto-converted to proper python type by `mapnik_value_to_python` - return i->second; - } - - static data_type - get(Container& container, index_type i_) - { - typename Container::iterator i = container.props().find(i_); - if (i != container.end()) - { - // will be auto-converted to proper python type by `mapnik_value_to_python` - return i->second; - } - return mapnik::value_null(); - } - - static void - set_item(Container& container, index_type i, data_type const& v) - { - container[i] = v; - } - - static void - delete_item(Container& container, index_type i) - { - container.props().erase(i); - } - - static size_t - size(Container& container) - { - return container.props().size(); - } - - static bool - contains(Container& container, key_type const& key) - { - return container.props().find(key) != container.end(); - } - - static bool - compare_index(Container& container, index_type a, index_type b) - { - return container.props().key_comp()(a, b); - } - - static index_type - convert_index(Container& /*container*/, PyObject* i_) - { - extract i(i_); - if (i.check()) - { - return i(); - } - else - { - extract i(i_); - if (i.check()) - return i(); - } - - PyErr_SetString(PyExc_TypeError, "Invalid index type"); - throw_error_already_set(); - return index_type(); - } - }; - - - template - struct std_pair_to_tuple - { - static PyObject* convert(std::pair const& p) - { - return boost::python::incref( - boost::python::make_tuple(p.first, p.second).ptr()); - } - }; - - template - struct std_pair_to_python_converter - { - std_pair_to_python_converter() - { - boost::python::to_python_converter< - std::pair, - std_pair_to_tuple >(); - } - }; - - }} +} // end anonymous namespace struct UnicodeString_from_python_str { @@ -260,27 +153,36 @@ void export_feature() using namespace boost::python; using mapnik::Feature; + // Python to mapnik::value converters implicitly_convertible(); implicitly_convertible(); implicitly_convertible(); implicitly_convertible(); - - std_pair_to_python_converter(); + UnicodeString_from_python_str(); - + + class_ + ("Context",init<>("Default ctor.")) + .def("push", &context_type::push) + ; + class_, - boost::noncopyable>("Feature",init("Default ctor.")) + boost::noncopyable>("Feature",init("Default ctor.")) .def("id",&Feature::id) .def("__str__",&Feature::to_string) .def("add_geometries_from_wkb", &feature_add_geometries_from_wkb) .def("add_geometries_from_wkt", &feature_add_geometries_from_wkt) - //.def("add_geometry", add_geometry) - //.def("num_geometries",&Feature::num_geometries) - //.def("get_geometry", make_function(get_geom1,return_value_policy())) - .def("geometries",make_function(&Feature::paths,return_value_policy())) + .def("add_geometry", &Feature::add_geometry) + .def("num_geometries",&Feature::num_geometries) + .def("get_geometry", make_function(get_geometry_by_const_ref,return_value_policy())) + .def("geometries",make_function(get_paths_by_const_ref,return_value_policy())) .def("envelope", &Feature::envelope) - .def(map_indexing_suite2()) - .def("iteritems",iterator ()) - // TODO define more mapnik::Feature methods + .def("has_key", &Feature::has_key) + .add_property("attributes",&attributes) + .def("__setitem__",&__setitem__) + .def("__getitem__",&__getitem__) + .def("__getitem__",&__getitem2__) + .def("__len__", &Feature::size) + .def("context",&Feature::context) ; } diff --git a/bindings/python/mapnik_palette.cpp b/bindings/python/mapnik_palette.cpp index 45866d318..4338055ae 100644 --- a/bindings/python/mapnik_palette.cpp +++ b/bindings/python/mapnik_palette.cpp @@ -43,11 +43,14 @@ static boost::shared_ptr make_palette( const std::string& void export_palette () { using namespace boost::python; - class_ >("Palette",no_init) - /*, init( - ( arg("palette"), arg("type")), - "Creates a new color palette from a file\n" - )*/ - .def( "__init__", boost::python::make_constructor(make_palette)) + + class_, + boost::noncopyable >("Palette",no_init) + //, init( + // ( arg("palette"), arg("type")), + // "Creates a new color palette from a file\n" + // ) + .def( "__init__", boost::python::make_constructor(make_palette)) ; } diff --git a/demo/python/rundemo.py b/demo/python/rundemo.py index d71a439fb..0fda7526d 100644 --- a/demo/python/rundemo.py +++ b/demo/python/rundemo.py @@ -368,6 +368,18 @@ if HAS_PYCAIRO_MODULE and mapnik.has_pycairo(): images_.append('demo.ps') postscript_surface.finish() + image_surface = cairo.ImageSurface(cairo.FORMAT_RGB24, m.width, m.height) + mapnik.render(m, image_surface) + image_surface.write_to_png('demo_cairo_rgb24.png') + images_.append('demo_cairo_argb24.png') + image_surface.finish() + + image_surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, m.width, m.height) + mapnik.render(m, image_surface) + image_surface.write_to_png('demo_cairo_argb32.png') + images_.append('demo_cairo_argb32.png') + image_surface.finish() + else: print '\n\nPycairo not available...', if mapnik.has_cairo(): @@ -379,9 +391,9 @@ else: images_.append('demo.ps') mapnik.render_to_file(m,'demo.svg') images_.append('demo.svg') - mapnik.render_to_file(m,'demo_cairo_rgb.png','RGB24') + mapnik.render_to_file(m,'demo_cairo_rgb24.png','RGB24') images_.append('demo_cairo_rgb.png') - mapnik.render_to_file(m,'demo_cairo_argb.png','ARGB32') + mapnik.render_to_file(m,'demo_cairo_argb32.png','ARGB32') images_.append('demo_cairo_argb.png') print "\n\n", len(images_), "maps have been rendered in the current directory:" diff --git a/demo/viewer/mapwidget.cpp b/demo/viewer/mapwidget.cpp index eafdb7adc..f9a29ee45 100644 --- a/demo/viewer/mapwidget.cpp +++ b/demo/viewer/mapwidget.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include "mapwidget.hpp" #include "info_dialog.hpp" @@ -42,6 +43,7 @@ using mapnik::geometry_ptr; using mapnik::CoordTransform; using mapnik::projection; using mapnik::scale_denominator; +using mapnik::feature_kv_iterator; double scales [] = {279541132.014, 139770566.007, @@ -170,17 +172,17 @@ void MapWidget::mousePressEvent(QMouseEvent* e) feature_ptr feat = fs->next(); if (feat) { - std::map const& props = feat->props(); - std::map::const_iterator itr=props.begin(); - for (; itr!=props.end();++itr) - { - if (itr->second.to_string().length() > 0) - { - info.push_back(QPair(QString(itr->first.c_str()), - itr->second.to_string().c_str())); - } - } - typedef mapnik::coord_transform2 path_type; + + feature_kv_iterator itr(*feat,true); + feature_kv_iterator end(*feat); + + for ( ;itr!=end; ++itr) + { + info.push_back(QPair(QString(boost::get<0>(*itr).c_str()), + boost::get<1>(*itr).to_string().c_str())); + } + + typedef mapnik::coord_transform2 path_type; for (unsigned i=0; inum_geometries();++i) { diff --git a/include/mapnik/attribute.hpp b/include/mapnik/attribute.hpp index d4172ab9c..bc37461b6 100644 --- a/include/mapnik/attribute.hpp +++ b/include/mapnik/attribute.hpp @@ -30,8 +30,6 @@ namespace mapnik { -static mapnik::value _null_value; - struct attribute { std::string name_; @@ -39,16 +37,11 @@ struct attribute : name_(name) {} template - V value(F const& f) const + V const& value(F const& f) const { - typedef typename F::const_iterator const_iterator; - const_iterator itr = f.find(name_); - if (itr != f.end()) - { - return itr->second; - } - return _null_value; + return f.get(name_); } + std::string const& name() const { return name_;} }; } diff --git a/include/mapnik/building_symbolizer.hpp b/include/mapnik/building_symbolizer.hpp new file mode 100644 index 000000000..08eed1bcb --- /dev/null +++ b/include/mapnik/building_symbolizer.hpp @@ -0,0 +1,53 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2011 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ + +#ifndef MAPNIK_BUILDING_SYMBOLIZER_HPP +#define MAPNIK_BUILDING_SYMBOLIZER_HPP + +// mapnik +#include +#include +#include + +namespace mapnik +{ + +struct MAPNIK_DECL building_symbolizer : public symbolizer_base +{ + building_symbolizer(); + building_symbolizer(color const& fill, expression_ptr height); + color const& get_fill() const; + void set_fill(color const& fill); + expression_ptr height() const; + void set_height(expression_ptr height); + void set_opacity(double opacity); + double get_opacity() const; + +private: + color fill_; + expression_ptr height_; + double opacity_; +}; + +} + +#endif // MAPNIK_BUILDING_SYMBOLIZER_HPP diff --git a/include/mapnik/datasource.hpp b/include/mapnik/datasource.hpp index 9934fa401..0902a72fb 100644 --- a/include/mapnik/datasource.hpp +++ b/include/mapnik/datasource.hpp @@ -43,7 +43,7 @@ namespace mapnik { typedef MAPNIK_DECL boost::shared_ptr feature_ptr; -struct MAPNIK_DECL Featureset +struct MAPNIK_DECL Featureset : private boost::noncopyable { virtual feature_ptr next()=0; virtual ~Featureset() {}; diff --git a/include/mapnik/feature.hpp b/include/mapnik/feature.hpp index fd8347a3e..082bb43b3 100644 --- a/include/mapnik/feature.hpp +++ b/include/mapnik/feature.hpp @@ -27,7 +27,7 @@ #include #include #include - +#include // boost #include #if BOOST_VERSION >= 104000 @@ -37,49 +37,154 @@ #endif #include #include +#include // stl +#include #include +#include namespace mapnik { -typedef boost::shared_ptr raster_ptr; -typedef boost::associative_property_map< -std::map > properties; - -template -struct feature : public properties, - private boost::noncopyable + +typedef boost::shared_ptr raster_ptr; + +class feature_impl; + +template +class context : private boost::noncopyable, + public boost::associative_property_map + { + friend class feature_impl; public: - typedef T1 geometry_type; - typedef T2 raster_type; - typedef std::map::value_type value_type; - typedef std::map::size_type size_type; - typedef std::map::difference_type difference_type; - -private: - int id_; - boost::ptr_vector geom_cont_; - raster_type raster_; - std::map props_; -public: - typedef std::map::iterator iterator; - typedef std::map::const_iterator const_iterator; - explicit feature(int id) - : properties(props_), - id_(id), - geom_cont_(), - raster_() {} - - int id() const + typedef T map_type; + typedef typename boost::associative_property_map base_type; + typedef typename map_type::value_type value_type; + typedef typename map_type::key_type key_type; + typedef typename map_type::size_type size_type; + typedef typename map_type::difference_type difference_type; + typedef typename map_type::iterator iterator; + typedef typename map_type::const_iterator const_iterator; + + context() + : base_type(mapping_) {} + + size_type push(key_type const& name) { - return id_; + size_type index = mapping_.size(); + mapping_.insert(std::make_pair(name, index)); + return index; + } + + size_type size() const { return mapping_.size(); } + const_iterator begin() const { return mapping_.begin();} + const_iterator end() const { return mapping_.end();} + +private: + map_type mapping_; +}; + +typedef context > context_type; +typedef boost::shared_ptr context_ptr; + +class feature_impl : private boost::noncopyable +{ + friend class feature_kv_iterator; +public: + + typedef mapnik::value value_type; + typedef std::vector cont_type; + typedef feature_kv_iterator iterator; + + feature_impl(context_ptr const& ctx, int id) + : id_(id), + ctx_(ctx), + data_(ctx_->mapping_.size()) + {} + + inline int id() const { return id_;} + + inline void set_id(int id) { id_ = id;} + + template + void put(context_type::key_type const& key, T const& val) + { + put(key,value(val)); + } + + template + void put_new(context_type::key_type const& key, T const& val) + { + put_new(key,value(val)); + } + + + void put(context_type::key_type const& key, value const& val) + { + context_type::map_type::const_iterator itr = ctx_->mapping_.find(key); + if (itr != ctx_->mapping_.end() + && itr->second < data_.size()) + { + data_[itr->second] = val; + } + else + throw std::out_of_range("Key doesn't exist"); } - void set_id(int id) + + void put_new(context_type::key_type const& key, value const& val) { - id_ = id; + context_type::map_type::const_iterator itr = ctx_->mapping_.find(key); + if (itr != ctx_->mapping_.end() + && itr->second < data_.size()) + { + data_[itr->second] = val; + } + else + { + cont_type::size_type index = ctx_->push(key); + if (index == data_.size()) + data_.push_back(val); + } + } + + + bool has_key(context_type::key_type const& key) const + { + return (ctx_->mapping_.find(key) != ctx_->mapping_.end()); + } + + value_type const& get(context_type::key_type const& key) const + { + context_type::map_type::const_iterator itr = ctx_->mapping_.find(key); + if (itr != ctx_->mapping_.end() + && itr->second < data_.size()) + { + return data_[itr->second]; + } + throw std::out_of_range("Key doesn't exist"); + } + + value_type const& get(std::size_t index) const + { + if (index < data_.size()) + return data_[index]; + throw std::out_of_range("Index out of range"); + } + + std::size_t size() const + { + return data_.size(); + } + + context_ptr context() + { + return ctx_; + } + + boost::ptr_vector const& paths() const + { + return geom_cont_; } boost::ptr_vector & paths() @@ -87,10 +192,9 @@ public: return geom_cont_; } - void add_geometry(geometry_type * geom) { - geom_cont_.push_back(geom); + geom_cont_.push_back(geom); } unsigned num_geometries() const @@ -107,7 +211,7 @@ public: { return geom_cont_[index]; } - + box2d envelope() const { box2d result; @@ -125,75 +229,59 @@ public: } } return result; - } - - const raster_type& get_raster() const + } + + const raster_ptr& get_raster() const { return raster_; } - - void set_raster(raster_type const& raster) - { - raster_=raster; - } - - std::map const& props() const - { - return props_; - } - - std::map& props() - { - return props_; - } - - iterator begin() - { - return props_.begin(); - } - - iterator end() - { - return props_.end(); - } - - const_iterator begin() const - { - return props_.begin(); - } - - const_iterator end() const - { - return props_.end(); - } - const_iterator find(std::string const& key) const + void set_raster(raster_ptr const& raster) { - return props_.find(key); + raster_ = raster; + } + + feature_kv_iterator begin() const + { + return feature_kv_iterator(*this,true); + } + + feature_kv_iterator end() const + { + return feature_kv_iterator(*this); } std::string to_string() const - { + { std::stringstream ss; - ss << "feature " - << id_ << " (" << std::endl; - for (std::map::const_iterator itr=props_.begin(); - itr != props_.end();++itr) + ss << "Feature (" << std::endl; + context_type::map_type::const_iterator itr = ctx_->mapping_.begin(); + context_type::map_type::const_iterator end = ctx_->mapping_.end(); + for ( ;itr!=end; ++itr) { - ss << " " << itr->first << ":" << itr->second << std::endl; + ss << " " << itr->first << ":" << data_[itr->second] << std::endl; } ss << ")" << std::endl; return ss.str(); } + +private: + int id_; + context_ptr ctx_; + boost::ptr_vector geom_cont_; + raster_ptr raster_; + cont_type data_; }; + -typedef feature Feature; - -inline std::ostream& operator<< (std::ostream & out,Feature const& f) +inline std::ostream& operator<< (std::ostream & out,feature_impl const& f) { out << f.to_string(); return out; } + +typedef feature_impl Feature; + } #endif // MAPNIK_FEATURE_HPP diff --git a/include/mapnik/feature_factory.hpp b/include/mapnik/feature_factory.hpp index dd550a16d..29921da64 100644 --- a/include/mapnik/feature_factory.hpp +++ b/include/mapnik/feature_factory.hpp @@ -34,11 +34,11 @@ namespace mapnik { struct feature_factory { - static boost::shared_ptr create (int fid) + static boost::shared_ptr create (context_ptr const& ctx, int fid) { //return boost::allocate_shared(boost::pool_allocator(),fid); //return boost::allocate_shared(boost::fast_pool_allocator(),fid); - return boost::make_shared(fid); + return boost::make_shared(ctx,fid); } }; } diff --git a/include/mapnik/feature_kv_iterator.hpp b/include/mapnik/feature_kv_iterator.hpp new file mode 100644 index 000000000..001302034 --- /dev/null +++ b/include/mapnik/feature_kv_iterator.hpp @@ -0,0 +1,63 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2012 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ + +#ifndef MAPNIK_FEATURE_KV_ITERATOR_HPP +#define MAPNIK_FEATURE_KV_ITERATOR_HPP + +#include +#include + +#include +//#include +#include + +namespace mapnik { + +class feature_impl; + +class feature_kv_iterator : + public boost::iterator_facade const, + boost::forward_traversal_tag> +{ +public: + typedef boost::tuple value_type; + + feature_kv_iterator (feature_impl const& f, bool begin = false); +private: + friend class boost::iterator_core_access; + void increment(); + + bool equal( feature_kv_iterator const& other) const; + + value_type const& dereference() const; + + feature_impl const& f_; + std::map::const_iterator itr_; + mutable value_type kv_; + +}; + +} + +#endif // MAPNIK_FEATURE_KV_ITERATOR_HPP + diff --git a/include/mapnik/geometry.hpp b/include/mapnik/geometry.hpp index 6ae01d179..1b07f4c86 100644 --- a/include/mapnik/geometry.hpp +++ b/include/mapnik/geometry.hpp @@ -35,6 +35,7 @@ namespace mapnik { enum eGeomType { + Unknown = 0, Point = 1, LineString = 2, Polygon = 3 @@ -53,6 +54,11 @@ private: mutable unsigned itr_; public: + geometry() + : type_(Unknown), + itr_(0) + {} + explicit geometry(eGeomType type) : type_(type), itr_(0) @@ -62,7 +68,12 @@ public: { return type_; } - + + void set_type(eGeomType type) + { + type_ = type; + } + container_type const& data() const { return cont_; diff --git a/include/mapnik/global.hpp b/include/mapnik/global.hpp index f834552c7..767ecc73a 100644 --- a/include/mapnik/global.hpp +++ b/include/mapnik/global.hpp @@ -74,7 +74,7 @@ typedef boost::uint8_t byte; // read int16_t NDR (little endian) -inline boost::int16_t& read_int16_ndr(const char* data, boost::int16_t & val) +inline void read_int16_ndr(const char* data, boost::int16_t & val) { #ifndef MAPNIK_BIG_ENDIAN std::memcpy(&val,data,2); @@ -82,11 +82,10 @@ inline boost::int16_t& read_int16_ndr(const char* data, boost::int16_t & val) val = (data[0]&0xff) | ((data[1]&0xff)<<8); #endif - return val; } // read int32_t NDR (little endian) -inline boost::int32_t& read_int32_ndr(const char* data, boost::int32_t & val) +inline void read_int32_ndr(const char* data, boost::int32_t & val) { #ifndef MAPNIK_BIG_ENDIAN std::memcpy(&val,data,4); @@ -96,11 +95,10 @@ inline boost::int32_t& read_int32_ndr(const char* data, boost::int32_t & val) ((data[2]&0xff)<<16) | ((data[3]&0xff)<<24); #endif - return val; } // read double NDR (little endian) -inline double& read_double_ndr(const char* data, double & val) +inline void read_double_ndr(const char* data, double & val) { #ifndef MAPNIK_BIG_ENDIAN std::memcpy(&val,&data[0],8); @@ -115,33 +113,30 @@ inline double& read_double_ndr(const char* data, double & val) ((boost::int64_t)data[7] & 0xff) << 56 ; std::memcpy(&val,&bits,8); #endif - return val; } // read int16_t XDR (big endian) -inline boost::int16_t& read_int16_xdr(const char* data, boost::int16_t & val) +inline void read_int16_xdr(const char* data, boost::int16_t & val) { #ifndef MAPNIK_BIG_ENDIAN val = (data[3]&0xff) | ((data[2]&0xff)<<8); #else std::memcpy(&val,data,2); #endif - return val; } // read int32_t XDR (big endian) -inline boost::int32_t& read_int32_xdr(const char* data, boost::int32_t & val) +inline void read_int32_xdr(const char* data, boost::int32_t & val) { #ifndef MAPNIK_BIG_ENDIAN val = (data[3]&0xff) | ((data[2]&0xff)<<8) | ((data[1]&0xff)<<16) | ((data[0]&0xff)<<24); #else std::memcpy(&val,data,4); #endif - return val; } // read double XDR (big endian) -inline double& read_double_xdr(const char* data, double & val) +inline void read_double_xdr(const char* data, double & val) { #ifndef MAPNIK_BIG_ENDIAN boost::int64_t bits = ((boost::int64_t)data[7] & 0xff) | @@ -156,7 +151,6 @@ inline double& read_double_xdr(const char* data, double & val) #else std::memcpy(&val,&data[0],8); #endif - return val; } #ifdef _WINDOWS diff --git a/include/mapnik/grid/grid.hpp b/include/mapnik/grid/grid.hpp index 37c7172af..398826139 100644 --- a/include/mapnik/grid/grid.hpp +++ b/include/mapnik/grid/grid.hpp @@ -110,8 +110,10 @@ public: inline void add_feature(mapnik::Feature const& feature) { - + // copies feature props + // FIXME + /* std::map fprops = feature.props(); lookup_type lookup_value; if (key_ == id_name_) @@ -153,6 +155,7 @@ public: { std::clog << "### Warning: key '" << key_ << "' was blank for " << feature << "\n"; } + */ } inline void add_property_name(std::string const& name) diff --git a/include/mapnik/memory_datasource.hpp b/include/mapnik/memory_datasource.hpp index 769a8efc8..4951c635d 100644 --- a/include/mapnik/memory_datasource.hpp +++ b/include/mapnik/memory_datasource.hpp @@ -52,19 +52,6 @@ private: mapnik::layer_descriptor desc_; }; -// This class implements a simple way of displaying point-based data -// TODO -- possible redesign, move into separate file -// - -class MAPNIK_DECL point_datasource : public memory_datasource { -public: - point_datasource() : - feature_id_(1) {} - void add_point(double x, double y, const char* key, const char* value); - -private: - int feature_id_; -}; } #endif // MAPNIK_MEMORY_DATASOURCE_HPP diff --git a/include/mapnik/metawriter.hpp b/include/mapnik/metawriter.hpp index 7bd2fc394..68792f4e4 100644 --- a/include/mapnik/metawriter.hpp +++ b/include/mapnik/metawriter.hpp @@ -61,6 +61,11 @@ public: { return m_.end(); } + + UnicodeString const& get(std::string const& key) const + { + return (*this)[key]; + } private: property_map m_; UnicodeString not_found_; diff --git a/include/mapnik/polygon_symbolizer.hpp b/include/mapnik/polygon_symbolizer.hpp index d9edf2eb0..3734a2edb 100644 --- a/include/mapnik/polygon_symbolizer.hpp +++ b/include/mapnik/polygon_symbolizer.hpp @@ -29,61 +29,22 @@ #include #include #include -// stl -#include namespace mapnik { struct MAPNIK_DECL polygon_symbolizer : public symbolizer_base { - polygon_symbolizer() - : symbolizer_base(), - fill_(color(128,128,128)), - opacity_(1.0), - gamma_(1.0), - gamma_method_(GAMMA_POWER) {} - - polygon_symbolizer(color const& fill) - : symbolizer_base(), - fill_(fill), - opacity_(1.0), - gamma_(1.0), - gamma_method_(GAMMA_POWER) {} - - color const& get_fill() const - { - return fill_; - } - - void set_fill(color const& fill) - { - fill_ = fill; - } - void set_opacity(double opacity) - { - opacity_ = opacity; - } - double get_opacity() const - { - return opacity_; - } - void set_gamma(double gamma) - { - gamma_ = gamma; - } - double get_gamma() const - { - return gamma_; - } - void set_gamma_method(gamma_method_e gamma_method) - { - gamma_method_ = gamma_method; - } - gamma_method_e get_gamma_method() const - { - return gamma_method_; - } + polygon_symbolizer(); + polygon_symbolizer(color const& fill); + color const& get_fill() const; + void set_fill(color const& fill); + void set_opacity(double opacity); + double get_opacity() const; + void set_gamma(double gamma); + double get_gamma() const; + void set_gamma_method(gamma_method_e gamma_method); + gamma_method_e get_gamma_method() const; private: color fill_; @@ -91,50 +52,7 @@ private: double gamma_; gamma_method_e gamma_method_; }; - -struct MAPNIK_DECL building_symbolizer : public symbolizer_base -{ - explicit building_symbolizer() - : symbolizer_base(), - fill_(color(128,128,128)), - opacity_(1.0) - {} - - building_symbolizer(color const& fill, expression_ptr height) - : symbolizer_base(), - fill_(fill), - height_(height), - opacity_(1.0) {} - - color const& get_fill() const - { - return fill_; - } - void set_fill(color const& fill) - { - fill_ = fill; - } - expression_ptr height() const - { - return height_; - } - void set_height(expression_ptr height) - { - height_=height; - } - void set_opacity(double opacity) - { - opacity_ = opacity; - } - double get_opacity() const - { - return opacity_; - } -private: - color fill_; - expression_ptr height_; - double opacity_; -}; + } #endif // MAPNIK_POLYGON_SYMBOLIZER_HPP diff --git a/include/mapnik/raster_colorizer.hpp b/include/mapnik/raster_colorizer.hpp index cdcf212ef..090900dd8 100644 --- a/include/mapnik/raster_colorizer.hpp +++ b/include/mapnik/raster_colorizer.hpp @@ -74,10 +74,13 @@ public: //! \param[in] value The stop value //! \param[in] mode The stop mode //! \param[in] color The stop color - colorizer_stop(const float value = 0, const colorizer_mode mode = COLORIZER_INHERIT, const color& _color = color(0,0,0,0), const std::string& label=""); + colorizer_stop(float value = 0, + colorizer_mode mode = COLORIZER_INHERIT, + color const& _color = color(0,0,0,0), + std::string const& label=""); //! \brief Copy constructor - colorizer_stop(const colorizer_stop& stop); + colorizer_stop(colorizer_stop const& stop); //! \brief Destructor ~colorizer_stop(); @@ -85,39 +88,39 @@ public: //! \brief Set the stop value //! \param[in] value The stop value - inline void set_value(const float value) { value_ = value; }; + inline void set_value(float value) { value_ = value; }; //! \brief Get the stop value //! \return The stop value - inline float get_value(void) const {return value_; }; + inline float get_value() const {return value_; }; //! \brief Set the stop mode //! \param[in] mode The stop mode - inline void set_mode(const colorizer_mode mode) { mode_ = mode; }; - inline void set_mode_enum(const colorizer_mode_enum mode) { set_mode(mode); }; + inline void set_mode(colorizer_mode mode) { mode_ = mode; }; + inline void set_mode_enum(colorizer_mode_enum mode) { set_mode(mode); }; //! \brief Get the stop mode //! \return The stop mode - inline colorizer_mode get_mode(void) const { return mode_; }; - inline colorizer_mode_enum get_mode_enum(void) const { return get_mode(); }; + inline colorizer_mode get_mode() const { return mode_; }; + inline colorizer_mode_enum get_mode_enum() const { return get_mode(); }; //! \brief set the stop color //! \param[in] the stop color - inline void set_color(const color& _color) { color_ = _color; }; + inline void set_color(color const& _color) { color_ = _color; }; //! \brief get the stop color //! \return The stop color - inline const color& get_color(void) const {return color_; }; + inline color const& get_color() const {return color_; }; //! \brief set the stop label //! \param[in] the stop label - inline void set_label(const std::string& label) { label_ = label; }; + inline void set_label(std::string const& label) { label_ = label; }; //! \brief get the stop label //! \return The stop label - inline const std::string& get_label(void) const {return label_; }; + inline std::string const& get_label() const {return label_; }; //! \brief Equality operator @@ -140,10 +143,11 @@ typedef std::vector colorizer_stops; //! \brief Class representing the raster colorizer -class MAPNIK_DECL raster_colorizer { +class MAPNIK_DECL raster_colorizer +{ public: //! \brief Constructor - raster_colorizer(colorizer_mode mode = COLORIZER_LINEAR, const color& _color = color(0,0,0,0)); + raster_colorizer(colorizer_mode mode = COLORIZER_LINEAR, color const& _color = color(0,0,0,0)); //! \brief Destructor ~raster_colorizer(); @@ -153,28 +157,33 @@ public: //! //! This can not be set as INHERIT, if you do, LINEAR will be used instead. //! \param[in] mode The default mode - void set_default_mode(const colorizer_mode mode) { default_mode_ = (mode == COLORIZER_INHERIT) ? COLORIZER_LINEAR:(colorizer_mode_enum)mode; }; - void set_default_mode_enum(const colorizer_mode_enum mode) { set_default_mode(mode); }; + + void set_default_mode(colorizer_mode mode) + { + default_mode_ = (mode == COLORIZER_INHERIT) ? COLORIZER_LINEAR:(colorizer_mode_enum)mode; + }; + + void set_default_mode_enum(colorizer_mode_enum mode) { set_default_mode(mode); }; //! \brief Get the default mode //! \return The default mode - colorizer_mode get_default_mode(void) const {return default_mode_; }; - colorizer_mode_enum get_default_mode_enum(void) const {return get_default_mode(); }; + colorizer_mode get_default_mode() const {return default_mode_; }; + colorizer_mode_enum get_default_mode_enum() const {return get_default_mode(); }; //! \brief Set the default color //! \param[in] color The default color - void set_default_color(const color& color) { default_color_ = color; }; + void set_default_color(color const& color) { default_color_ = color; }; //! \brief Get the default color //! \return The default color - const color& get_default_color(void) const {return default_color_; }; + color const& get_default_color() const {return default_color_; }; //! \brief Add a stop //! //! \param[in] stop The stop to add //! \return True if added, false if error - bool add_stop(const colorizer_stop & stop); + bool add_stop(colorizer_stop const& stop); //! \brief Set the list of stops //! \param[in] stops The list of stops @@ -182,16 +191,16 @@ public: //! \brief Get the list of stops //! \return The list of stops - const colorizer_stops& get_stops(void) const {return stops_; }; + colorizer_stops const& get_stops() const {return stops_; }; //! \brief Colorize a raster //! //! \param[in, out] raster A raster stored in float32 single channel format, which gets colorized in place. - //! \param[in] properties belonging to the feature, used to find 'NODATA' information if available - void colorize(raster_ptr const& raster,const std::map &Props) const; - + //! \param[in] feature used to find 'NODATA' information if available + void colorize(raster_ptr const& raster, Feature const& f) const; + //! \brief Perform the translation of input to output //! //! \param[in] value Input value @@ -205,7 +214,7 @@ public: //! \brief Get the epsilon value for exact mode //! \return The epsilon value - inline float get_epsilon(void) const { return epsilon_; }; + inline float get_epsilon() const { return epsilon_; }; private: colorizer_stops stops_; //!< The vector of stops diff --git a/include/mapnik/rule.hpp b/include/mapnik/rule.hpp index 9e811bf3f..9895578c3 100644 --- a/include/mapnik/rule.hpp +++ b/include/mapnik/rule.hpp @@ -23,7 +23,8 @@ #ifndef MAPNIK_RULE_HPP #define MAPNIK_RULE_HPP -// mapnik +// mapni +#include #include #include #include diff --git a/include/mapnik/text_placements.hpp b/include/mapnik/text_placements.hpp index 195b2ac8d..ab90c6768 100644 --- a/include/mapnik/text_placements.hpp +++ b/include/mapnik/text_placements.hpp @@ -167,6 +167,11 @@ public: */ virtual bool next()=0; virtual ~text_placement_info() {} + /** Initialize values used by placement finder. Only has to be done once + * per object. + */ + void init(double scale_factor_, + unsigned w = 0, unsigned h = 0, bool has_dimensions_ = false); /** Properties actually used by placement finder and renderer. Values in * here are modified each time next() is called. */ diff --git a/plugins/input/csv/csv_datasource.cpp b/plugins/input/csv/csv_datasource.cpp index d7f63b4ff..b923affad 100644 --- a/plugins/input/csv/csv_datasource.cpp +++ b/plugins/input/csv/csv_datasource.cpp @@ -389,7 +389,14 @@ void csv_datasource::parse_csv(T& stream, int feature_count(1); bool extent_initialized = false; - unsigned num_headers = headers_.size(); + std::size_t num_headers = headers_.size(); + + ctx_ = boost::make_shared(); + for (std::size_t i = 0; i < headers_.size(); ++i) + { + ctx_->push(headers_[i]); + } + mapnik::transcoder tr(desc_.get_encoding()); while (std::getline(stream,csv_line,newline)) @@ -435,7 +442,7 @@ void csv_datasource::parse_csv(T& stream, } } - mapnik::feature_ptr feature(mapnik::feature_factory::create(feature_count)); + mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx_,feature_count)); double x(0); double y(0); bool parsed_x = false; @@ -451,9 +458,7 @@ void csv_datasource::parse_csv(T& stream, std::string value; if (beg == tok.end()) { - UnicodeString ustr = tr.transcode(value.c_str()); - boost::put(*feature,fld_name,ustr); - // boost::put(*feature,fld_name,mapnik::value_null()); + feature->put(fld_name,tr.transcode(value.c_str())); null_geom = true; if (feature_count == 1) { @@ -633,8 +638,7 @@ void csv_datasource::parse_csv(T& stream, (value_length > 20) || (value_length > 1 && !has_dot && value[0] == '0')) { - UnicodeString ustr = tr.transcode(value.c_str()); - boost::put(*feature,fld_name,ustr); + feature->put(fld_name,tr.transcode(value.c_str())); if (feature_count == 1) { desc_.add_descriptor(mapnik::attribute_descriptor(fld_name,mapnik::String)); @@ -650,7 +654,7 @@ void csv_datasource::parse_csv(T& stream, { if (has_dot) { - boost::put(*feature,fld_name,float_val); + feature->put(fld_name,float_val); if (feature_count == 1) { desc_.add_descriptor( @@ -660,8 +664,7 @@ void csv_datasource::parse_csv(T& stream, } else { - int val = static_cast(float_val); - boost::put(*feature,fld_name,val); + feature->put(fld_name,static_cast(float_val)); if (feature_count == 1) { desc_.add_descriptor( @@ -673,8 +676,7 @@ void csv_datasource::parse_csv(T& stream, else { // fallback to normal string - UnicodeString ustr = tr.transcode(value.c_str()); - boost::put(*feature,fld_name,ustr); + feature->put(fld_name,tr.transcode(value.c_str())); if (feature_count == 1) { desc_.add_descriptor( @@ -686,8 +688,7 @@ void csv_datasource::parse_csv(T& stream, else { // fallback to normal string - UnicodeString ustr = tr.transcode(value.c_str()); - boost::put(*feature,fld_name,ustr); + feature->put(fld_name,tr.transcode(value.c_str())); if (feature_count == 1) { desc_.add_descriptor( @@ -889,7 +890,7 @@ mapnik::featureset_ptr csv_datasource::features(mapnik::query const& q) const while (pos != attribute_names.end()) { bool found_name = false; - for (int i = 0; i < headers_.size(); ++i) + for (std::size_t i = 0; i < headers_.size(); ++i) { if (headers_[i] == *pos) { diff --git a/plugins/input/csv/csv_datasource.hpp b/plugins/input/csv/csv_datasource.hpp index e9e28b1a6..985d73242 100644 --- a/plugins/input/csv/csv_datasource.hpp +++ b/plugins/input/csv/csv_datasource.hpp @@ -41,6 +41,7 @@ private: mutable bool strict_; mutable bool quiet_; mutable double filesize_max_; + mutable mapnik::context_ptr ctx_; }; diff --git a/plugins/input/gdal/gdal_featureset.cpp b/plugins/input/gdal/gdal_featureset.cpp index 09c2b10c8..a5ccfd51b 100644 --- a/plugins/input/gdal/gdal_featureset.cpp +++ b/plugins/input/gdal/gdal_featureset.cpp @@ -55,6 +55,7 @@ gdal_featureset::gdal_featureset(GDALDataset& dataset, double dy, double filter_factor) : dataset_(dataset), + ctx_(boost::make_shared()), band_(band), gquery_(q), raster_extent_(extent), @@ -66,6 +67,8 @@ gdal_featureset::gdal_featureset(GDALDataset& dataset, filter_factor_(filter_factor), first_(true) { + ctx_->push("value"); + ctx_->push("NODATA"); } gdal_featureset::~gdal_featureset() @@ -106,14 +109,14 @@ feature_ptr gdal_featureset::next() feature_ptr gdal_featureset::get_feature(mapnik::query const& q) { - feature_ptr feature(feature_factory::create(1)); - + feature_ptr feature = feature_factory::create(ctx_,1); + GDALRasterBand * red = 0; GDALRasterBand * green = 0; GDALRasterBand * blue = 0; GDALRasterBand * alpha = 0; GDALRasterBand * grey = 0; - + /* double tr[6]; dataset_.GetGeoTransform(tr); @@ -244,10 +247,10 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q) imageData, image.width(), image.height(), GDT_Float32, 0, 0); - feature->set_raster(mapnik::raster_ptr(boost::make_shared(intersect,image))); + feature->set_raster(boost::make_shared(intersect,image)); if (hasNoData) { - feature->props()["NODATA"] = nodata; + feature->put("NODATA",nodata); } } else // working with all bands @@ -487,12 +490,12 @@ feature_ptr gdal_featureset::get_feature_at_point(mapnik::coord2d const& pt) if (! hasNoData || value != nodata) { - // construct feature - feature_ptr feature(new Feature(1)); + // construct feature + feature_ptr feature = feature_factory::create(ctx_,1); geometry_type * point = new geometry_type(mapnik::Point); point->move_to(pt.x, pt.y); feature->add_geometry(point); - (*feature)["value"] = value; + feature->put("value",value); return feature; } } diff --git a/plugins/input/gdal/gdal_featureset.hpp b/plugins/input/gdal/gdal_featureset.hpp index 5dc08ac8a..d4a2e9db8 100644 --- a/plugins/input/gdal/gdal_featureset.hpp +++ b/plugins/input/gdal/gdal_featureset.hpp @@ -24,6 +24,7 @@ #define GDAL_FEATURESET_HPP // mapnik +#include #include // boost @@ -56,6 +57,7 @@ private: void get_overview_meta(GDALRasterBand * band); #endif GDALDataset & dataset_; + mapnik::context_ptr ctx_; int band_; gdal_query gquery_; mapnik::box2d raster_extent_; diff --git a/plugins/input/geos/geos_featureset.cpp b/plugins/input/geos/geos_featureset.cpp index afd2d71af..dc76c8cb6 100644 --- a/plugins/input/geos/geos_featureset.cpp +++ b/plugins/input/geos/geos_featureset.cpp @@ -60,8 +60,10 @@ geos_featureset::geos_featureset(GEOSGeometry* geometry, identifier_(identifier), field_(field), field_name_(field_name), - already_rendered_(false) + already_rendered_(false), + ctx_(boost::make_shared()) { + ctx_->push(field_name); } geos_featureset::~geos_featureset() @@ -114,14 +116,14 @@ feature_ptr geos_featureset::next() geos_wkb_ptr wkb(geometry_); if (wkb.is_valid()) { - feature_ptr feature(feature_factory::create(identifier_)); + feature_ptr feature(feature_factory::create(ctx_,identifier_)); geometry_utils::from_wkb(feature->paths(), wkb.data(), wkb.size()); if (field_ != "") { - boost::put(*feature, field_name_, tr_->transcode(field_.c_str())); + feature->put(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 713f9ff4c..f3fcb9d81 100644 --- a/plugins/input/geos/geos_featureset.hpp +++ b/plugins/input/geos/geos_featureset.hpp @@ -56,6 +56,7 @@ private: std::string field_; std::string field_name_; bool already_rendered_; + mapnik::context_ptr ctx_; geos_featureset(const geos_featureset&); const geos_featureset& operator=(const geos_featureset&); diff --git a/plugins/input/kismet/kismet_featureset.cpp b/plugins/input/kismet/kismet_featureset.cpp index ab1d198fa..5a1642b64 100644 --- a/plugins/input/kismet/kismet_featureset.cpp +++ b/plugins/input/kismet/kismet_featureset.cpp @@ -40,15 +40,17 @@ using mapnik::geometry_utils; using mapnik::transcoder; using mapnik::feature_factory; -kismet_featureset::kismet_featureset(const std::list& knd_list, +kismet_featureset::kismet_featureset(std::list const& knd_list, std::string const& srs, std::string const& encoding) : knd_list_(knd_list), tr_(new transcoder(encoding)), feature_id_(1), knd_list_it(knd_list_.begin()), - source_(srs) + source_(srs), + ctx_(boost::make_shared()) { + ctx_->push("internet_access"); } kismet_featureset::~kismet_featureset() @@ -76,14 +78,14 @@ feature_ptr kismet_featureset::next() value = "wlan_crypted"; } - feature_ptr feature(feature_factory::create(feature_id_)); + feature_ptr feature(feature_factory::create(ctx_,feature_id_)); ++feature_id_; geometry_type* pt = new geometry_type(mapnik::Point); pt->move_to(knd.bestlon(), knd.bestlat()); feature->add_geometry(pt); - boost::put(*feature, key, tr_->transcode(value.c_str())); + feature->put(key, tr_->transcode(value.c_str())); ++knd_list_it; diff --git a/plugins/input/kismet/kismet_featureset.hpp b/plugins/input/kismet/kismet_featureset.hpp index 363f3425a..0efdf537c 100644 --- a/plugins/input/kismet/kismet_featureset.hpp +++ b/plugins/input/kismet/kismet_featureset.hpp @@ -40,19 +40,20 @@ class kismet_featureset : public mapnik::Featureset { public: - kismet_featureset(const std::list& knd_list, + kismet_featureset(std::list const& knd_list, std::string const& srs, std::string const& encoding); virtual ~kismet_featureset(); mapnik::feature_ptr next(); private: - const std::list& knd_list_; + std::list const& knd_list_; boost::scoped_ptr tr_; mapnik::wkbFormat format_; int feature_id_; std::list::const_iterator knd_list_it; mapnik::projection source_; + mapnik::context_ptr ctx_; }; #endif // KISMET_FEATURESET_HPP diff --git a/plugins/input/occi/occi_datasource.cpp b/plugins/input/occi/occi_datasource.cpp index 5cb1aedcb..59248c562 100644 --- a/plugins/input/occi/occi_datasource.cpp +++ b/plugins/input/occi/occi_datasource.cpp @@ -500,10 +500,11 @@ featureset_ptr occi_datasource::features(query const& q) const std::set const& props = q.property_names(); std::set::const_iterator pos = props.begin(); std::set::const_iterator end = props.end(); - while (pos != end) + mapnik::context_ptr ctx = boost::make_shared(); + for ( ;pos != end;++pos) { s << ", " << *pos; - ++pos; + ctx->push(*pos); } s << " FROM "; @@ -565,11 +566,11 @@ featureset_ptr occi_datasource::features(query const& q) const return boost::make_shared(pool_, conn_, + ctx, s.str(), desc_.get_encoding(), use_connection_pool_, - row_prefetch_, - props.size()); + row_prefetch_); } featureset_ptr occi_datasource::features_at_point(coord2d const& pt) const @@ -580,12 +581,12 @@ featureset_ptr occi_datasource::features_at_point(coord2d const& pt) const s << "SELECT " << geometry_field_; std::vector::const_iterator itr = desc_.get_descriptors().begin(); std::vector::const_iterator end = desc_.get_descriptors().end(); - unsigned size = 0; + mapnik::context_ptr ctx = boost::make_shared(); while (itr != end) { s << ", " << itr->get_name(); + ctx->push(itr->get_name()); ++itr; - ++size; } s << " FROM "; @@ -646,9 +647,9 @@ featureset_ptr occi_datasource::features_at_point(coord2d const& pt) const return boost::make_shared(pool_, conn_, + ctx, s.str(), desc_.get_encoding(), use_connection_pool_, - row_prefetch_, - size); + row_prefetch_); } diff --git a/plugins/input/occi/occi_featureset.cpp b/plugins/input/occi/occi_featureset.cpp index b4ea397ad..22073a7c8 100644 --- a/plugins/input/occi/occi_featureset.cpp +++ b/plugins/input/occi/occi_featureset.cpp @@ -57,14 +57,14 @@ using oracle::occi::Blob; occi_featureset::occi_featureset(StatelessConnectionPool* pool, Connection* conn, + mapnik::context_ptr const& ctx, std::string const& sqlstring, std::string const& encoding, bool use_connection_pool, - unsigned prefetch_rows, - unsigned num_attrs) + unsigned prefetch_rows) : tr_(new transcoder(encoding)), - num_attrs_(num_attrs), - feature_id_(1) + feature_id_(1), + ctx_(ctx) { if (use_connection_pool) { @@ -93,7 +93,7 @@ feature_ptr occi_featureset::next() { if (rs_ && rs_->next()) { - feature_ptr feature(feature_factory::create(feature_id_)); + feature_ptr feature(feature_factory::create(ctx_,feature_id_)); ++feature_id_; boost::scoped_ptr geom(dynamic_cast(rs_->getObject(1))); @@ -125,7 +125,7 @@ feature_ptr occi_featureset::next() case oracle::occi::OCCIINT: case oracle::occi::OCCIUNSIGNED_INT: case oracle::occi::OCCIROWID: - boost::put(*feature,fld_name,rs_->getInt (i + 1)); + feature->put(fld_name,rs_->getInt (i + 1)); break; case oracle::occi::OCCIFLOAT: case oracle::occi::OCCIBFLOAT: @@ -133,7 +133,7 @@ feature_ptr occi_featureset::next() case oracle::occi::OCCIBDOUBLE: case oracle::occi::OCCINUMBER: case oracle::occi::OCCI_SQLT_NUM: - boost::put(*feature,fld_name,rs_->getDouble (i + 1)); + feature->put(fld_name,rs_->getDouble (i + 1)); break; case oracle::occi::OCCICHAR: case oracle::occi::OCCISTRING: @@ -147,7 +147,7 @@ feature_ptr occi_featureset::next() case oracle::occi::OCCI_SQLT_VNU: case oracle::occi::OCCI_SQLT_VBI: case oracle::occi::OCCI_SQLT_VST: - boost::put(*feature,fld_name,(UnicodeString) tr_->transcode (rs_->getString (i + 1).c_str())); + feature->put(fld_name,(UnicodeString) tr_->transcode (rs_->getString (i + 1).c_str())); break; case oracle::occi::OCCIDATE: case oracle::occi::OCCITIMESTAMP: diff --git a/plugins/input/occi/occi_featureset.hpp b/plugins/input/occi/occi_featureset.hpp index 4c2a0db67..1ad3be653 100644 --- a/plugins/input/occi/occi_featureset.hpp +++ b/plugins/input/occi/occi_featureset.hpp @@ -40,11 +40,11 @@ class occi_featureset : public mapnik::Featureset public: occi_featureset(oracle::occi::StatelessConnectionPool* pool, oracle::occi::Connection* conn, + mapnik::context_ptr const& ctx, std::string const& sqlstring, std::string const& encoding, bool use_connection_pool, - unsigned prefetch_rows, - unsigned num_attrs); + unsigned prefetch_rows); virtual ~occi_featureset(); mapnik::feature_ptr next(); @@ -68,8 +68,8 @@ private: oracle::occi::ResultSet* rs_; boost::scoped_ptr tr_; const char* fidcolumn_; - unsigned num_attrs_; mutable int feature_id_; + mapnik::context_ptr ctx_; }; #endif // OCCI_FEATURESET_HPP diff --git a/plugins/input/ogr/ogr_datasource.cpp b/plugins/input/ogr/ogr_datasource.cpp index c187980a3..410f8b516 100644 --- a/plugins/input/ogr/ogr_datasource.cpp +++ b/plugins/input/ogr/ogr_datasource.cpp @@ -38,6 +38,7 @@ // boost #include +#include using mapnik::datasource; using mapnik::parameters; @@ -428,56 +429,70 @@ layer_descriptor ogr_datasource::get_descriptor() const return desc_; } +void validate_attribute_names(query const& q, std::vector const& names ) +{ + std::set const& attribute_names = q.property_names(); + std::set::const_iterator pos = attribute_names.begin(); + std::set::const_iterator end_names = attribute_names.end(); + + for ( ;pos != end_names; ++pos) + { + bool found_name = false; + + std::vector::const_iterator itr = names.begin(); + std::vector::const_iterator end = names.end(); + + for (; itr!=end; ++itr) + { + if (itr->get_name() == *pos) + { + found_name = true; + break; + } + } + + if (! found_name) + { + std::ostringstream s; + std::vector::const_iterator itr = names.begin(); + std::vector::const_iterator end = names.end(); + s << "OGR Plugin: no attribute '" << *pos << "'. Valid attributes are: "; + for ( ;itr!=end;++itr) + { + s << itr->get_name() << std::endl; + } + throw mapnik::datasource_exception(s.str()); + } + } +} + featureset_ptr ogr_datasource::features(query const& q) const { if (! is_bound_) bind(); if (dataset_ && layer_.is_valid()) { - // First we validate query fields: https://github.com/mapnik/mapnik/issues/792 + // First we validate query fields: https://github.com/mapnik/mapnik/issues/792 + std::vector const& desc_ar = desc_.get_descriptors(); - std::vector::const_iterator it = desc_ar.begin(); + // feature context (schema) + mapnik::context_ptr ctx = boost::make_shared(); + + std::vector::const_iterator itr = desc_ar.begin(); std::vector::const_iterator end = desc_ar.end(); - std::vector known_fields; - for (; it != end; ++it) - { - known_fields.push_back(it->get_name()); - } - - const std::set& attribute_names = q.property_names(); - std::set::const_iterator pos = attribute_names.begin(); - while (pos != attribute_names.end()) - { - bool found_name = false; - for (int i = 0; i < known_fields.size(); ++i) - { - if (known_fields[i] == *pos) - { - found_name = true; - break; - } - } - - if (! found_name) - { - std::ostringstream s; - - s << "OGR Plugin: no attribute '" << *pos << "'. Valid attributes are: " - << boost::algorithm::join(known_fields, ",") << "."; - - throw mapnik::datasource_exception(s.str()); - } - ++pos; - } - - + + for (; itr!=end; ++itr) ctx->push(itr->get_name()); // TODO only push query attributes + + validate_attribute_names(q, desc_ar); + OGRLayer* layer = layer_.layer(); if (indexed_) { filter_in_box filter(q.get_bbox()); - return featureset_ptr(new ogr_index_featureset(*dataset_, + return featureset_ptr(new ogr_index_featureset(ctx, + *dataset_, *layer, filter, index_name_, @@ -486,7 +501,8 @@ featureset_ptr ogr_datasource::features(query const& q) const } else { - return featureset_ptr(new ogr_featureset (*dataset_, + return featureset_ptr(new ogr_featureset (ctx, + *dataset_, *layer, q.get_bbox(), desc_.get_encoding() @@ -503,13 +519,22 @@ featureset_ptr ogr_datasource::features_at_point(coord2d const& pt) const if (dataset_ && layer_.is_valid()) { + std::vector const& desc_ar = desc_.get_descriptors(); + // feature context (schema) + mapnik::context_ptr ctx = boost::make_shared(); + + std::vector::const_iterator itr = desc_ar.begin(); + std::vector::const_iterator end = desc_ar.end(); + for (; itr!=end; ++itr) ctx->push(itr->get_name()); + OGRLayer* layer = layer_.layer(); - + if (indexed_) { filter_at_point filter(pt); - - return featureset_ptr(new ogr_index_featureset (*dataset_, + + return featureset_ptr(new ogr_index_featureset (ctx, + *dataset_, *layer, filter, index_name_, @@ -522,7 +547,8 @@ featureset_ptr ogr_datasource::features_at_point(coord2d const& pt) const point.setX (pt.x); point.setY (pt.y); - return featureset_ptr(new ogr_featureset (*dataset_, + return featureset_ptr(new ogr_featureset (ctx, + *dataset_, *layer, point, desc_.get_encoding() diff --git a/plugins/input/ogr/ogr_featureset.cpp b/plugins/input/ogr/ogr_featureset.cpp index 2e916a4bb..30248e0fc 100644 --- a/plugins/input/ogr/ogr_featureset.cpp +++ b/plugins/input/ogr/ogr_featureset.cpp @@ -46,25 +46,30 @@ using mapnik::transcoder; using mapnik::feature_factory; -ogr_featureset::ogr_featureset(OGRDataSource & dataset, +ogr_featureset::ogr_featureset(mapnik::context_ptr const & ctx, + OGRDataSource & dataset, OGRLayer & layer, OGRGeometry & extent, - const std::string& encoding) - : dataset_(dataset), + std::string const& encoding) + : ctx_(ctx), + dataset_(dataset), layer_(layer), layerdef_(layer.GetLayerDefn()), tr_(new transcoder(encoding)), fidcolumn_(layer_.GetFIDColumn ()), count_(0) + { layer_.SetSpatialFilter (&extent); } -ogr_featureset::ogr_featureset(OGRDataSource & dataset, +ogr_featureset::ogr_featureset(mapnik::context_ptr const& ctx, + OGRDataSource & dataset, OGRLayer & layer, - const mapnik::box2d & extent, - const std::string& encoding) - : dataset_(dataset), + mapnik::box2d const& extent, + std::string const& encoding) + : ctx_(ctx), + dataset_(dataset), layer_(layer), layerdef_(layer.GetLayerDefn()), tr_(new transcoder(encoding)), @@ -90,7 +95,7 @@ feature_ptr ogr_featureset::next() // ogr feature ids start at 0, so add one to stay // consistent with other mapnik datasources that start at 1 const int feature_id = ((*feat)->GetFID() + 1); - feature_ptr feature(feature_factory::create(feature_id)); + feature_ptr feature(feature_factory::create(ctx_,feature_id)); OGRGeometry* geom = (*feat)->GetGeometryRef(); if (geom && ! geom->IsEmpty()) @@ -117,13 +122,13 @@ feature_ptr ogr_featureset::next() { case OFTInteger: { - boost::put(*feature, fld_name, (*feat)->GetFieldAsInteger(i)); + feature->put( fld_name, (*feat)->GetFieldAsInteger(i)); break; } case OFTReal: { - boost::put(*feature, fld_name, (*feat)->GetFieldAsDouble(i)); + feature->put( fld_name, (*feat)->GetFieldAsDouble(i)); break; } @@ -131,7 +136,7 @@ feature_ptr ogr_featureset::next() case OFTWideString: // deprecated ! { UnicodeString ustr = tr_->transcode((*feat)->GetFieldAsString(i)); - boost::put(*feature, fld_name, ustr); + feature->put( fld_name, ustr); break; } @@ -151,7 +156,7 @@ feature_ptr ogr_featureset::next() #ifdef MAPNIK_DEBUG std::clog << "OGR Plugin: unhandled type_oid=" << type_oid << std::endl; #endif - //boost::put(*feature,name,feat->GetFieldAsBinary (i, size)); + //feature->put(name,feat->GetFieldAsBinary (i, size)); break; } diff --git a/plugins/input/ogr/ogr_featureset.hpp b/plugins/input/ogr/ogr_featureset.hpp index 7e30a1ab1..f13c699b1 100644 --- a/plugins/input/ogr/ogr_featureset.hpp +++ b/plugins/input/ogr/ogr_featureset.hpp @@ -37,28 +37,30 @@ class ogr_featureset : public mapnik::Featureset { public: - ogr_featureset(OGRDataSource & dataset, + ogr_featureset(mapnik::context_ptr const& ctx, + OGRDataSource & dataset, OGRLayer & layer, OGRGeometry & extent, - const std::string& encoding); + std::string const& encoding); - ogr_featureset(OGRDataSource & dataset, + ogr_featureset(mapnik::context_ptr const& ctx, + OGRDataSource & dataset, OGRLayer & layer, - const mapnik::box2d & extent, - const std::string& encoding); + mapnik::box2d const& extent, + std::string const& encoding); + virtual ~ogr_featureset(); mapnik::feature_ptr next(); private: - ogr_featureset(const ogr_featureset&); - const ogr_featureset& operator=(const ogr_featureset&); - + mapnik::context_ptr ctx_; OGRDataSource& dataset_; OGRLayer& layer_; OGRFeatureDefn* layerdef_; boost::scoped_ptr tr_; const char* fidcolumn_; mutable int count_; + }; #endif // OGR_FEATURESET_HPP diff --git a/plugins/input/ogr/ogr_index_featureset.cpp b/plugins/input/ogr/ogr_index_featureset.cpp index 399a0aa65..8a007fe08 100644 --- a/plugins/input/ogr/ogr_index_featureset.cpp +++ b/plugins/input/ogr/ogr_index_featureset.cpp @@ -52,12 +52,14 @@ using mapnik::transcoder; using mapnik::feature_factory; template -ogr_index_featureset::ogr_index_featureset(OGRDataSource & dataset, +ogr_index_featureset::ogr_index_featureset(mapnik::context_ptr const & ctx, + OGRDataSource & dataset, OGRLayer & layer, - const filterT& filter, - const std::string& index_file, - const std::string& encoding) - : dataset_(dataset), + filterT const& filter, + std::string const& index_file, + std::string const& encoding) + : ctx_(ctx), + dataset_(dataset), layer_(layer), layerdef_(layer.GetLayerDefn()), filter_(filter), @@ -101,7 +103,7 @@ feature_ptr ogr_index_featureset::next() // ogr feature ids start at 0, so add one to stay // consistent with other mapnik datasources that start at 1 int feature_id = ((*feat)->GetFID() + 1); - feature_ptr feature(feature_factory::create(feature_id)); + feature_ptr feature(feature_factory::create(ctx_,feature_id)); OGRGeometry* geom=(*feat)->GetGeometryRef(); if (geom && !geom->IsEmpty()) @@ -126,13 +128,13 @@ feature_ptr ogr_index_featureset::next() { case OFTInteger: { - boost::put(*feature,fld_name,(*feat)->GetFieldAsInteger (i)); + feature->put(fld_name,(*feat)->GetFieldAsInteger (i)); break; } case OFTReal: { - boost::put(*feature,fld_name,(*feat)->GetFieldAsDouble (i)); + feature->put(fld_name,(*feat)->GetFieldAsDouble (i)); break; } @@ -140,7 +142,7 @@ feature_ptr ogr_index_featureset::next() case OFTWideString: // deprecated ! { UnicodeString ustr = tr_->transcode((*feat)->GetFieldAsString (i)); - boost::put(*feature,fld_name,ustr); + feature->put(fld_name,ustr); break; } @@ -160,7 +162,7 @@ feature_ptr ogr_index_featureset::next() #ifdef MAPNIK_DEBUG std::clog << "OGR Plugin: unhandled type_oid=" << type_oid << std::endl; #endif - //boost::put(*feature,name,feat->GetFieldAsBinary (i, size)); + //feature->put(name,feat->GetFieldAsBinary (i, size)); break; } diff --git a/plugins/input/ogr/ogr_index_featureset.hpp b/plugins/input/ogr/ogr_index_featureset.hpp index 1d76f914b..7bb163ca7 100644 --- a/plugins/input/ogr/ogr_index_featureset.hpp +++ b/plugins/input/ogr/ogr_index_featureset.hpp @@ -32,18 +32,18 @@ template class ogr_index_featureset : public mapnik::Featureset { public: - ogr_index_featureset(OGRDataSource& dataset, + ogr_index_featureset(mapnik::context_ptr const& ctx, + OGRDataSource& dataset, OGRLayer& layer, - const filterT& filter, - const std::string& index_file, - const std::string& encoding); + filterT const& filter, + std::string const& index_file, + std::string const& encoding); + virtual ~ogr_index_featureset(); mapnik::feature_ptr next(); private: - ogr_index_featureset(const ogr_index_featureset&); - ogr_index_featureset& operator=(const ogr_index_featureset&); - + mapnik::context_ptr ctx_; OGRDataSource& dataset_; OGRLayer& layer_; OGRFeatureDefn* layerdef_; @@ -52,6 +52,7 @@ private: std::vector::iterator itr_; boost::scoped_ptr tr_; const char* fidcolumn_; + }; #endif // OGR_INDEX_FEATURESET_HPP diff --git a/plugins/input/osm/osm_featureset.cpp b/plugins/input/osm/osm_featureset.cpp index 279797706..420861aa6 100644 --- a/plugins/input/osm/osm_featureset.cpp +++ b/plugins/input/osm/osm_featureset.cpp @@ -46,7 +46,8 @@ osm_featureset::osm_featureset(const filterT& filter, tr_(new transcoder(encoding)), feature_id_(1), dataset_ (dataset), - attribute_names_ (attribute_names) + attribute_names_ (attribute_names), + ctx_(boost::make_shared()) { dataset_->rewind(); } @@ -62,7 +63,7 @@ feature_ptr osm_featureset::next() { if (dataset_->current_item_is_node()) { - feature = feature_factory::create(feature_id_); + feature = feature_factory::create(ctx_,feature_id_); ++feature_id_; double lat = static_cast(cur_item)->lat; double lon = static_cast(cur_item)->lon; @@ -90,7 +91,7 @@ feature_ptr osm_featureset::next() { if (static_cast(cur_item)->nodes.size()) { - feature = feature_factory::create(feature_id_); + feature = feature_factory::create(ctx_,feature_id_); ++feature_id_; geometry_type* geom; if (static_cast(cur_item)->is_polygon()) @@ -131,7 +132,7 @@ feature_ptr osm_featureset::next() // only add if in the specified set of attribute names if (attribute_names_.find(i->first) != attribute_names_.end()) { - (*feature)[i->first] = tr_->transcode(i->second.c_str()); + feature->put(i->first,tr_->transcode(i->second.c_str())); } i++; diff --git a/plugins/input/osm/osm_featureset.hpp b/plugins/input/osm/osm_featureset.hpp index e93d1952c..dd4e9ad3a 100644 --- a/plugins/input/osm/osm_featureset.hpp +++ b/plugins/input/osm/osm_featureset.hpp @@ -63,6 +63,7 @@ private: mutable int feature_id_; osm_dataset *dataset_; std::set attribute_names_; + mapnik::context_ptr ctx_; // no copying osm_featureset(const osm_featureset&); const osm_featureset& operator=(const osm_featureset&); diff --git a/plugins/input/postgis/postgis_datasource.cpp b/plugins/input/postgis/postgis_datasource.cpp index b6059b090..4417d16a1 100644 --- a/plugins/input/postgis/postgis_datasource.cpp +++ b/plugins/input/postgis/postgis_datasource.cpp @@ -497,7 +497,7 @@ featureset_ptr postgis_datasource::features(const query& q) const s_error << geometry_table_ << "'."; throw mapnik::datasource_exception(s_error.str()); } - + std::ostringstream s; s << "SELECT ST_AsBinary(\"" << geometryColumn_ << "\") AS geom"; @@ -507,10 +507,13 @@ featureset_ptr postgis_datasource::features(const query& q) const std::set const& props=q.property_names(); std::set::const_iterator pos=props.begin(); std::set::const_iterator end=props.end(); - while (pos != end) + + mapnik::context_ptr ctx = boost::make_shared(); + + for ( ;pos != end;++pos) { mapnik::sql_utils::quote_attr(s,*pos); - ++pos; + ctx->push(*pos); } std::string table_with_bbox = populate_tokens(table_,scale_denom,box); @@ -525,7 +528,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(), !key_field_.empty(),num_attr); + return boost::make_shared(rs, ctx, desc_.get_encoding(), !key_field_.empty()); } else { @@ -573,14 +576,15 @@ featureset_ptr postgis_datasource::features_at_point(coord2d const& pt) const if (!key_field_.empty()) mapnik::sql_utils::quote_attr(s,key_field_); + mapnik::context_ptr ctx = boost::make_shared(); + std::vector::const_iterator itr = desc_.get_descriptors().begin(); std::vector::const_iterator end = desc_.get_descriptors().end(); - unsigned size=0; - while (itr != end) + + for ( ; itr != end; ++itr) { mapnik::sql_utils::quote_attr(s,itr->get_name()); - ++itr; - ++size; + ctx->push(itr->get_name()); } box2d box(pt.x,pt.y,pt.x,pt.y); @@ -593,7 +597,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(), !key_field_.empty(),size); + return boost::make_shared(rs, ctx, desc_.get_encoding(), !key_field_.empty()); } } return featureset_ptr(); diff --git a/plugins/input/postgis/postgis_featureset.cpp b/plugins/input/postgis/postgis_featureset.cpp index 087047ce5..0db3060f9 100644 --- a/plugins/input/postgis/postgis_featureset.cpp +++ b/plugins/input/postgis/postgis_featureset.cpp @@ -46,13 +46,14 @@ using mapnik::geometry_type; using mapnik::byte; using mapnik::geometry_utils; using mapnik::feature_factory; +using mapnik::context_ptr; postgis_featureset::postgis_featureset(boost::shared_ptr const& rs, + context_ptr const& ctx, std::string const& encoding, - bool key_field=false, - unsigned num_attrs=0) + bool key_field) : rs_(rs), - num_attrs_(num_attrs), + ctx_(ctx), tr_(new transcoder(encoding)), totalGeomSize_(0), feature_id_(1), @@ -86,15 +87,15 @@ feature_ptr postgis_featureset::next() { val = int4net(buf); } - feature = feature_factory::create(val); + feature = feature_factory::create(ctx_, val); // TODO - extend feature class to know // that its id is also an attribute to avoid // this duplication - boost::put(*feature,name,val); + feature->put(name,val); ++pos; } else { // fallback to auto-incrementing id - feature = feature_factory::create(feature_id_); + feature = feature_factory::create(ctx_,feature_id_); ++feature_id_; } @@ -104,59 +105,59 @@ feature_ptr postgis_featureset::next() geometry_utils::from_wkb(feature->paths(), data, size); totalGeomSize_+=size; - for ( ;possize() + 1; + for ( ; pos < num_attrs; ++pos) { std::string name = rs_->getFieldName(pos); - + if (rs_->isNull(pos)) { - boost::put(*feature,name,mapnik::value_null()); + feature->put(name,mapnik::value_null()); } else { const char* buf = rs_->getValue(pos); int oid = rs_->getTypeOID(pos); - + if (oid==16) //bool { - boost::put(*feature,name,buf[0] != 0); + feature->put(name,(buf[0] != 0)); } else if (oid==23) //int4 { int val = int4net(buf); - boost::put(*feature,name,val); + feature->put(name,val); } else if (oid==21) //int2 { int val = int2net(buf); - boost::put(*feature,name,val); + feature->put(name,val); } else if (oid==20) //int8/BigInt { int val = int8net(buf); - boost::put(*feature,name,val); + feature->put(name,val); } else if (oid == 700) // float4 { float val; float4net(val,buf); - boost::put(*feature,name,val); + feature->put(name,val); } else if (oid == 701) // float8 { double val; float8net(val,buf); - boost::put(*feature,name,val); + feature->put(name,val); } else if (oid==25 || oid==1043) // text or varchar { - UnicodeString ustr = tr_->transcode(buf); - boost::put(*feature,name,ustr); + feature->put(name,tr_->transcode(buf)); } else if (oid==1042) { - UnicodeString ustr = tr_->transcode(trim_copy(std::string(buf)).c_str()); // bpchar - boost::put(*feature,name,ustr); + // bpchar + feature->put(name,tr_->transcode(trim_copy(std::string(buf)).c_str())); } else if (oid == 1700) // numeric { @@ -164,7 +165,7 @@ feature_ptr postgis_featureset::next() try { double val = boost::lexical_cast(str); - boost::put(*feature,name,val); + feature->put(name,val); } catch (boost::bad_lexical_cast & ex) { diff --git a/plugins/input/postgis/postgis_featureset.hpp b/plugins/input/postgis/postgis_featureset.hpp index fbb0e2adc..7ed317a32 100644 --- a/plugins/input/postgis/postgis_featureset.hpp +++ b/plugins/input/postgis/postgis_featureset.hpp @@ -37,6 +37,7 @@ using mapnik::Featureset; using mapnik::box2d; using mapnik::feature_ptr; using mapnik::transcoder; +using mapnik::context_ptr; class IResultSet; @@ -44,21 +45,18 @@ class postgis_featureset : public mapnik::Featureset { private: boost::shared_ptr rs_; - unsigned num_attrs_; + context_ptr ctx_; boost::scoped_ptr tr_; int totalGeomSize_; int feature_id_; bool key_field_; public: postgis_featureset(boost::shared_ptr const& rs, + context_ptr const& ctx, std::string const& encoding, - bool key_field, - unsigned num_attrs); - mapnik::feature_ptr next(); + bool key_field = false); + feature_ptr next(); ~postgis_featureset(); -private: - postgis_featureset(const postgis_featureset&); - const postgis_featureset& operator=(const postgis_featureset&); }; #endif // POSTGIS_FEATURESET_HPP diff --git a/plugins/input/raster/raster_featureset.cpp b/plugins/input/raster/raster_featureset.cpp index 9144a38a4..7352e56aa 100644 --- a/plugins/input/raster/raster_featureset.cpp +++ b/plugins/input/raster/raster_featureset.cpp @@ -50,6 +50,7 @@ raster_featureset::raster_featureset(LookupPolicy const& policy, curIter_(policy_.begin()), endIter_(policy_.end()) { + ctx_ = boost::make_shared(); } template @@ -62,9 +63,8 @@ feature_ptr raster_featureset::next() { if (curIter_ != endIter_) { - feature_ptr feature(feature_factory::create(feature_id_)); - ++feature_id_; - + feature_ptr feature(feature_factory::create(ctx_,feature_id_++)); + try { std::auto_ptr reader(mapnik::get_image_reader(curIter_->file(),curIter_->format())); diff --git a/plugins/input/raster/raster_featureset.hpp b/plugins/input/raster/raster_featureset.hpp index a70a4471d..22998fa32 100644 --- a/plugins/input/raster/raster_featureset.hpp +++ b/plugins/input/raster/raster_featureset.hpp @@ -310,6 +310,7 @@ class raster_featureset : public mapnik::Featureset typedef typename LookupPolicy::const_iterator iterator_type; LookupPolicy policy_; int feature_id_; + mapnik::context_ptr ctx_; mapnik::box2d extent_; mapnik::box2d bbox_; iterator_type curIter_; diff --git a/plugins/input/shape/build.py b/plugins/input/shape/build.py index 70771927e..5501bddf7 100644 --- a/plugins/input/shape/build.py +++ b/plugins/input/shape/build.py @@ -34,6 +34,7 @@ shape_src = Split( shape_featureset.cpp shape_index_featureset.cpp shape_io.cpp + shape_utils.cpp """ ) diff --git a/plugins/input/shape/dbfile.cpp b/plugins/input/shape/dbfile.cpp index fa1a6a966..9e09a14f3 100644 --- a/plugins/input/shape/dbfile.cpp +++ b/plugins/input/shape/dbfile.cpp @@ -121,7 +121,7 @@ const field_descriptor& dbf_file::descriptor(int col) const } -void dbf_file::add_attribute(int col, mapnik::transcoder const& tr, Feature const& f) const throw() +void dbf_file::add_attribute(int col, mapnik::transcoder const& tr, Feature & f) const throw() { using namespace boost::spirit; @@ -139,7 +139,7 @@ void dbf_file::add_attribute(int col, mapnik::transcoder const& tr, Feature cons // FIXME - avoid constructing std::string on stack std::string str(record_+fields_[col].offset_,fields_[col].length_); boost::trim(str); - f[name] = tr.transcode(str.c_str()); + f.put(name,tr.transcode(str.c_str())); break; } case 'N': @@ -148,7 +148,7 @@ void dbf_file::add_attribute(int col, mapnik::transcoder const& tr, Feature cons if (record_[fields_[col].offset_] == '*') { - boost::put(f,name,0); + f.put(name,0); break; } if ( fields_[col].dec_>0 ) @@ -157,7 +157,7 @@ void dbf_file::add_attribute(int col, mapnik::transcoder const& tr, Feature cons const char *itr = record_+fields_[col].offset_; const char *end = itr + fields_[col].length_; qi::phrase_parse(itr,end,double_,ascii::space,val); - boost::put(f,name,val); + f.put(name,val); } else { @@ -165,7 +165,7 @@ void dbf_file::add_attribute(int col, mapnik::transcoder const& tr, Feature cons const char *itr = record_+fields_[col].offset_; const char *end = itr + fields_[col].length_; qi::phrase_parse(itr,end,int_,ascii::space,val); - boost::put(f,name,val); + f.put(name,val); } break; } diff --git a/plugins/input/shape/dbfile.hpp b/plugins/input/shape/dbfile.hpp index 743b985f6..263fcaddf 100644 --- a/plugins/input/shape/dbfile.hpp +++ b/plugins/input/shape/dbfile.hpp @@ -71,7 +71,7 @@ public: field_descriptor const& descriptor(int col) const; void move_to(int index); std::string string_value(int col) const; - void add_attribute(int col, transcoder const& tr, Feature const& f) const throw(); + void add_attribute(int col, transcoder const& tr, Feature & f) const throw(); private: void read_header(); int read_short(); diff --git a/plugins/input/shape/shape_featureset.cpp b/plugins/input/shape/shape_featureset.cpp index 779c3869d..29d48c524 100644 --- a/plugins/input/shape/shape_featureset.cpp +++ b/plugins/input/shape/shape_featureset.cpp @@ -1,4 +1,3 @@ - /***************************************************************************** * * This file is part of Mapnik (c++ mapping toolkit) @@ -27,65 +26,31 @@ // mapnik #include -// boost -#include - #include "shape_featureset.hpp" +#include "shape_utils.hpp" using mapnik::geometry_type; using mapnik::feature_factory; - +using mapnik::context_ptr; + template -shape_featureset::shape_featureset(const filterT& filter, - const std::string& shape_name, - const std::set& attribute_names, +shape_featureset::shape_featureset(filterT const& filter, + std::string const& shape_name, + std::set const& attribute_names, std::string const& encoding, long file_length, int row_limit) : filter_(filter), - //shape_type_(shape_io::shape_null), shape_(shape_name, false), query_ext_(), tr_(new transcoder(encoding)), file_length_(file_length), - count_(0), - row_limit_(row_limit) + row_limit_(row_limit), + count_(0) { + ctx_ = boost::make_shared(); shape_.shp().skip(100); - - //attributes - typename std::set::const_iterator pos = attribute_names.begin(); - while (pos != attribute_names.end()) - { - bool found_name = false; - for (int i = 0; i < shape_.dbf().num_fields(); ++i) - { - if (shape_.dbf().descriptor(i).name_ == *pos) - { - attr_ids_.push_back(i); - found_name = true; - break; - } - } - - if (! found_name) - { - std::ostringstream s; - - s << "no attribute '" << *pos << "' in '" - << shape_name << "'. Valid attributes are: "; - - std::vector list; - for (int i = 0; i < shape_.dbf().num_fields(); ++i) - { - list.push_back(shape_.dbf().descriptor(i).name_); - } - s << boost::algorithm::join(list, ",") << "."; - - throw mapnik::datasource_exception("Shape Plugin: " + s.str()); - } - ++pos; - } + setup_attributes(ctx_, attribute_names, shape_name, shape_,attr_ids_); } template @@ -115,7 +80,7 @@ feature_ptr shape_featureset::next() if (pos < std::streampos(file_length_ * 2)) { int type = shape_.type(); - feature_ptr feature(feature_factory::create(shape_.id_)); + feature_ptr feature(feature_factory::create(ctx_, shape_.id_)); if (type == shape_io::shape_point) { @@ -266,7 +231,7 @@ feature_ptr shape_featureset::next() } } } - + // FIXME: https://github.com/mapnik/mapnik/issues/1020 feature->set_id(shape_.id_); if (attr_ids_.size()) { diff --git a/plugins/input/shape/shape_featureset.hpp b/plugins/input/shape/shape_featureset.hpp index ae671829f..2d2a12755 100644 --- a/plugins/input/shape/shape_featureset.hpp +++ b/plugins/input/shape/shape_featureset.hpp @@ -31,41 +31,36 @@ //boost #include +#include using mapnik::Featureset; using mapnik::box2d; using mapnik::feature_ptr; using mapnik::transcoder; +using mapnik::context_ptr; template class shape_featureset : public Featureset { filterT filter_; - //int shape_type_; + context_ptr ctx_; shape_io shape_; box2d query_ext_; boost::scoped_ptr tr_; long file_length_; std::vector attr_ids_; - mutable box2d feature_ext_; - mutable int total_geom_size; - mutable int count_; const int row_limit_; - + mutable int count_; + public: - shape_featureset(const filterT& filter, - const std::string& shape_file, - const std::set& attribute_names, + shape_featureset(filterT const& filter, + std::string const& shape_file, + std::set const& attribute_names, std::string const& encoding, long file_length, int row_limit); virtual ~shape_featureset(); feature_ptr next(); - -private: - shape_featureset(const shape_featureset&); - const shape_featureset& operator=(const shape_featureset&); - }; #endif //SHAPE_FEATURESET_HPP diff --git a/plugins/input/shape/shape_index_featureset.cpp b/plugins/input/shape/shape_index_featureset.cpp index 0c0fcadc5..f6fe6f212 100644 --- a/plugins/input/shape/shape_index_featureset.cpp +++ b/plugins/input/shape/shape_index_featureset.cpp @@ -31,26 +31,28 @@ #include #include "shape_index_featureset.hpp" +#include "shape_utils.hpp" using mapnik::feature_factory; using mapnik::geometry_type; template -shape_index_featureset::shape_index_featureset(const filterT& filter, +shape_index_featureset::shape_index_featureset(filterT const& filter, shape_io& shape, - const std::set& attribute_names, + std::set const& attribute_names, std::string const& encoding, std::string const& shape_name, int row_limit) : filter_(filter), - //shape_type_(0), shape_(shape), tr_(new transcoder(encoding)), - count_(0), - row_limit_(row_limit) + row_limit_(row_limit), + count_(0) { + ctx_ = boost::make_shared(); shape_.shp().skip(100); - + setup_attributes(ctx_, attribute_names, shape_name, shape_,attr_ids_); + boost::shared_ptr index = shape_.index(); if (index) { @@ -63,46 +65,12 @@ shape_index_featureset::shape_index_featureset(const filterT& filter, } std::sort(ids_.begin(), ids_.end()); - + #ifdef MAPNIK_DEBUG std::clog << "Shape Plugin: query size=" << ids_.size() << std::endl; #endif - - itr_ = ids_.begin(); - - // deal with attributes - std::set::const_iterator pos = attribute_names.begin(); - while (pos != attribute_names.end()) - { - bool found_name = false; - for (int i = 0; i < shape_.dbf().num_fields(); ++i) - { - if (shape_.dbf().descriptor(i).name_ == *pos) - { - attr_ids_.insert(i); - found_name = true; - break; - } - } - - if (! found_name) - { - std::ostringstream s; - s << "no attribute '" << *pos << "' in '" << shape_name << "'. Valid attributes are: "; - - std::vector list; - for (int i = 0; i < shape_.dbf().num_fields(); ++i) - { - list.push_back(shape_.dbf().descriptor(i).name_); - } - - s << boost::algorithm::join(list, ",") << "."; - - throw mapnik::datasource_exception("Shape Plugin: " + s.str()); - } - - ++pos; - } + + itr_ = ids_.begin(); } template @@ -119,7 +87,7 @@ feature_ptr shape_index_featureset::next() shape_.move_to(pos); int type = shape_.type(); - feature_ptr feature(feature_factory::create(shape_.id_)); + feature_ptr feature(feature_factory::create(ctx_,shape_.id_)); if (type == shape_io::shape_point) { double x = shape_.shp().read_double(); @@ -210,13 +178,13 @@ feature_ptr shape_index_featureset::next() } } } - + // FIXME feature->set_id(shape_.id_); if (attr_ids_.size()) { shape_.dbf().move_to(shape_.id_); - std::set::const_iterator itr = attr_ids_.begin(); - std::set::const_iterator end = attr_ids_.end(); + std::vector::const_iterator itr = attr_ids_.begin(); + std::vector::const_iterator end = attr_ids_.end(); try { for (; itr!=end; ++itr) diff --git a/plugins/input/shape/shape_index_featureset.hpp b/plugins/input/shape/shape_index_featureset.hpp index 3e0fad5a3..528d5f3ea 100644 --- a/plugins/input/shape/shape_index_featureset.hpp +++ b/plugins/input/shape/shape_index_featureset.hpp @@ -32,6 +32,7 @@ // boost #include +#include #include "shape_datasource.hpp" #include "shape_io.hpp" @@ -39,35 +40,33 @@ using mapnik::Featureset; using mapnik::box2d; using mapnik::feature_ptr; +using mapnik::context_ptr; template -class shape_index_featureset : public Featureset +class shape_index_featureset : public Featureset { public: - shape_index_featureset(const filterT& filter, - shape_io& shape, - const std::set& attribute_names, + shape_index_featureset(filterT const& filter, + shape_io & shape, + std::set const& attribute_names, std::string const& encoding, std::string const& shape_name, int row_limit); + virtual ~shape_index_featureset(); + feature_ptr next(); private: filterT filter_; - //int shape_type_; + context_ptr ctx_; shape_io & shape_; boost::scoped_ptr tr_; std::vector ids_; std::vector::iterator itr_; - std::set attr_ids_; - mutable box2d feature_ext_; - mutable int total_geom_size; - mutable int count_; + std::vector attr_ids_; const int row_limit_; - //no copying - shape_index_featureset(const shape_index_featureset&); - shape_index_featureset& operator=(const shape_index_featureset&); + mutable int count_; }; #endif // SHAPE_INDEX_FEATURESET_HPP diff --git a/plugins/input/shape/shape_io.cpp b/plugins/input/shape/shape_io.cpp index bb9d24973..647fc7d9a 100644 --- a/plugins/input/shape/shape_io.cpp +++ b/plugins/input/shape/shape_io.cpp @@ -94,13 +94,6 @@ shape_file& shape_io::shp() return shp_; } -#if 0 -shape_file& shape_io::shx() -{ - return shx_; -} -#endif - dbf_file& shape_io::dbf() { return dbf_; diff --git a/plugins/input/shape/shape_utils.cpp b/plugins/input/shape/shape_utils.cpp new file mode 100644 index 000000000..d83db47dd --- /dev/null +++ b/plugins/input/shape/shape_utils.cpp @@ -0,0 +1,73 @@ +/***************************************************************************** + * + * 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 + * + *****************************************************************************/ + +// mapnik +#include +#include "shape_utils.hpp" + +// boost +#include +// stl +#include +#include + + +void setup_attributes(mapnik::context_ptr const& ctx, + std::set const& names, + std::string const& shape_name, + shape_io & shape, + std::vector & attr_ids) +{ + std::set::const_iterator pos = names.begin(); + std::set::const_iterator end = names.end(); + for ( ;pos !=end; ++pos) + { + bool found_name = false; + for (int i = 0; i < shape.dbf().num_fields(); ++i) + { + if (shape.dbf().descriptor(i).name_ == *pos) + { + ctx->push(*pos); + attr_ids.push_back(i); + found_name = true; + break; + } + } + + if (! found_name) + { + std::ostringstream s; + + s << "no attribute '" << *pos << "' in '" + << shape_name << "'. Valid attributes are: "; + + std::vector list; + for (int i = 0; i < shape.dbf().num_fields(); ++i) + { + list.push_back(shape.dbf().descriptor(i).name_); + } + s << boost::algorithm::join(list, ",") << "."; + + throw mapnik::datasource_exception("Shape Plugin: " + s.str()); + } + } +} diff --git a/plugins/input/shape/shape_utils.hpp b/plugins/input/shape/shape_utils.hpp new file mode 100644 index 000000000..cbffa5c3a --- /dev/null +++ b/plugins/input/shape/shape_utils.hpp @@ -0,0 +1,40 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2011 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ + +#ifndef SHAPE_UTILS_HPP +#define SHAPE_UTILS_HPP + +// mapnik +#include +#include "shape_io.hpp" +// stl +#include +#include +#include + +void setup_attributes(mapnik::context_ptr const& ctx, + std::set const& names, + std::string const& shape_name, + shape_io & shape, + std::vector & attr_ids); + +#endif // SHAPE_UTILS_HPP diff --git a/plugins/input/sqlite/sqlite_datasource.cpp b/plugins/input/sqlite/sqlite_datasource.cpp index 2cd3f11e0..7a7529584 100644 --- a/plugins/input/sqlite/sqlite_datasource.cpp +++ b/plugins/input/sqlite/sqlite_datasource.cpp @@ -547,19 +547,24 @@ featureset_ptr sqlite_datasource::features(query const& q) const mapnik::box2d const& e = q.get_bbox(); std::ostringstream s; + mapnik::context_ptr ctx = boost::make_shared(); s << "SELECT " << geometry_field_; if (!key_field_.empty()) + { s << "," << key_field_; + ctx->push(key_field_); + } std::set const& props = q.property_names(); std::set::const_iterator pos = props.begin(); std::set::const_iterator end = props.end(); - while (pos != end) + + for ( ;pos != end;++pos) { // TODO - should we restrict duplicate key query? //if (*pos != key_field_) s << ",[" << *pos << "]"; - ++pos; + ctx->push(*pos); } s << " FROM "; @@ -601,6 +606,7 @@ featureset_ptr sqlite_datasource::features(query const& q) const boost::shared_ptr rs(dataset_->execute_query(s.str())); return boost::make_shared(rs, + ctx, desc_.get_encoding(), format_, using_subquery_); @@ -619,20 +625,26 @@ featureset_ptr sqlite_datasource::features_at_point(coord2d const& pt) const mapnik::box2d const e(pt.x, pt.y, pt.x, pt.y); std::ostringstream s; + mapnik::context_ptr ctx = boost::make_shared(); + s << "SELECT " << geometry_field_; if (!key_field_.empty()) + { s << "," << key_field_; + ctx->push(key_field_); + } + std::vector::const_iterator itr = desc_.get_descriptors().begin(); std::vector::const_iterator end = desc_.get_descriptors().end(); - while (itr != end) + + for ( ; itr != end; ++itr) { std::string fld_name = itr->get_name(); if (fld_name != key_field_) { s << ",[" << itr->get_name() << "]"; + ctx->push(itr->get_name()); } - - ++itr; } s << " FROM "; @@ -674,6 +686,7 @@ featureset_ptr sqlite_datasource::features_at_point(coord2d const& pt) const boost::shared_ptr rs(dataset_->execute_query(s.str())); return boost::make_shared(rs, + ctx, desc_.get_encoding(), format_, using_subquery_); diff --git a/plugins/input/sqlite/sqlite_featureset.cpp b/plugins/input/sqlite/sqlite_featureset.cpp index f92a8ba46..dc9aeb5d8 100644 --- a/plugins/input/sqlite/sqlite_featureset.cpp +++ b/plugins/input/sqlite/sqlite_featureset.cpp @@ -45,13 +45,15 @@ using mapnik::transcoder; using mapnik::feature_factory; sqlite_featureset::sqlite_featureset(boost::shared_ptr rs, + mapnik::context_ptr const& ctx, std::string const& encoding, mapnik::wkbFormat format, bool using_subquery) : rs_(rs), tr_(new transcoder(encoding)), format_(format), - using_subquery_(using_subquery) + using_subquery_(using_subquery), + ctx_(ctx) { } @@ -70,9 +72,7 @@ feature_ptr sqlite_featureset::next() return feature_ptr(); } - int feature_id = rs_->column_integer(1); - - feature_ptr feature(feature_factory::create(feature_id)); + feature_ptr feature(feature_factory::create(ctx_,rs_->column_integer(1))); geometry_utils::from_wkb(feature->paths(), data, size, format_); for (int i = 2; i < rs_->column_count(); ++i) @@ -95,13 +95,13 @@ feature_ptr sqlite_featureset::next() { case SQLITE_INTEGER: { - boost::put(*feature, fld_name_str, rs_->column_integer(i)); + feature->put(fld_name_str, rs_->column_integer(i)); break; } case SQLITE_FLOAT: { - boost::put(*feature, fld_name_str, rs_->column_double(i)); + feature->put(fld_name_str, rs_->column_double(i)); break; } @@ -110,13 +110,13 @@ feature_ptr sqlite_featureset::next() int text_size; const char * data = rs_->column_text(i, text_size); UnicodeString ustr = tr_->transcode(data, text_size); - boost::put(*feature, fld_name_str, ustr); + feature->put(fld_name_str, ustr); break; } case SQLITE_NULL: { - boost::put(*feature, fld_name_str, mapnik::value_null()); + feature->put(fld_name_str, mapnik::value_null()); break; } diff --git a/plugins/input/sqlite/sqlite_featureset.hpp b/plugins/input/sqlite/sqlite_featureset.hpp index 4ec7472ba..b7feb7386 100644 --- a/plugins/input/sqlite/sqlite_featureset.hpp +++ b/plugins/input/sqlite/sqlite_featureset.hpp @@ -40,6 +40,7 @@ class sqlite_featureset : public mapnik::Featureset { public: sqlite_featureset(boost::shared_ptr rs, + mapnik::context_ptr const& ctx, std::string const& encoding, mapnik::wkbFormat format, bool using_subquery); @@ -51,6 +52,7 @@ private: boost::scoped_ptr tr_; mapnik::wkbFormat format_; bool using_subquery_; + mapnik::context_ptr ctx_; }; #endif // MAPNIK_SQLITE_FEATURESET_HPP diff --git a/plugins/input/templates/helloworld/hello_datasource.cpp b/plugins/input/templates/helloworld/hello_datasource.cpp index e8023bbfb..8bcd2283c 100644 --- a/plugins/input/templates/helloworld/hello_datasource.cpp +++ b/plugins/input/templates/helloworld/hello_datasource.cpp @@ -12,7 +12,7 @@ using mapnik::parameters; DATASOURCE_PLUGIN(hello_datasource) hello_datasource::hello_datasource(parameters const& params, bool bind) -: datasource(params) +: datasource(params), desc_(*params_.get("type"), *params_.get("encoding","utf-8")), extent_() { @@ -33,10 +33,6 @@ void hello_datasource::bind() const // see http://spatialreference.org/ref/epsg/4326/ for more details extent_.init(-180,-90,180,90); - // declare that this datasource is going to provide points - // options are point,polygon,linestring, and collection - desc_.set_geometry_type("point"); - is_bound_ = true; } @@ -64,7 +60,7 @@ mapnik::box2d hello_datasource::envelope() const boost::optional hello_datasource::get_geometry_type() const { - boost::optional(mapnik::datasource::Point); + return mapnik::datasource::Point; } mapnik::layer_descriptor hello_datasource::get_descriptor() const diff --git a/plugins/input/templates/helloworld/hello_featureset.cpp b/plugins/input/templates/helloworld/hello_featureset.cpp index 9107d10f7..eb3f19a10 100644 --- a/plugins/input/templates/helloworld/hello_featureset.cpp +++ b/plugins/input/templates/helloworld/hello_featureset.cpp @@ -7,7 +7,8 @@ hello_featureset::hello_featureset(mapnik::box2d const& box, std::string const& encoding) : box_(box), feature_id_(1), - tr_(new mapnik::transcoder(encoding)) { } + tr_(new mapnik::transcoder(encoding)), + ctx_(boost::make_shared()) { } hello_featureset::~hello_featureset() { } @@ -16,14 +17,14 @@ mapnik::feature_ptr hello_featureset::next() if (feature_id_ == 1) { // create a new feature - mapnik::feature_ptr feature(mapnik::feature_factory::create(feature_id_)); + mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx_,feature_id_)); // increment the count so that we only return one feature ++feature_id_; // create an attribute pair of key:value UnicodeString ustr = tr_->transcode("hello world!"); - boost::put(*feature,"key",ustr); + feature->put("key",ustr); // we need a geometry to display so just for fun here // we take the center of the bbox that was used to query diff --git a/plugins/input/templates/helloworld/hello_featureset.hpp b/plugins/input/templates/helloworld/hello_featureset.hpp index 57c4021f5..ffdce76f6 100644 --- a/plugins/input/templates/helloworld/hello_featureset.hpp +++ b/plugins/input/templates/helloworld/hello_featureset.hpp @@ -25,6 +25,7 @@ private: mapnik::box2d const& box_; mutable int feature_id_; boost::scoped_ptr tr_; + mapnik::context_ptr ctx_; }; #endif // HELLO_FEATURESET_HPP diff --git a/src/agg/process_raster_symbolizer.cpp b/src/agg/process_raster_symbolizer.cpp index 0f3e062f0..248109b57 100644 --- a/src/agg/process_raster_symbolizer.cpp +++ b/src/agg/process_raster_symbolizer.cpp @@ -49,8 +49,8 @@ void agg_renderer::process(raster_symbolizer const& sym, // If there's a colorizer defined, use it to color the raster in-place raster_colorizer_ptr colorizer = sym.get_colorizer(); if (colorizer) - colorizer->colorize(source,feature.props()); - + colorizer->colorize(source,feature); + box2d target_ext = box2d(source->ext_); prj_trans.backward(target_ext, PROJ_ENVELOPE_POINTS); diff --git a/src/build.py b/src/build.py index 1520e9dd9..1fc21f836 100644 --- a/src/build.py +++ b/src/build.py @@ -105,11 +105,13 @@ source = Split( """ color.cpp box2d.cpp + building_symbolizer.cpp datasource_cache.cpp deepcopy.cpp expression_string.cpp filter_factory.cpp - feature_type_style.cpp + feature_kv_iterator.cpp + feature_type_style.cpp font_engine_freetype.cpp font_set.cpp gamma_method.cpp diff --git a/src/building_symbolizer.cpp b/src/building_symbolizer.cpp new file mode 100644 index 000000000..44baf2701 --- /dev/null +++ b/src/building_symbolizer.cpp @@ -0,0 +1,72 @@ +/***************************************************************************** + * + * 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$ + +// mapnik +#include + +namespace mapnik +{ + +building_symbolizer::building_symbolizer() + : symbolizer_base(), + fill_(color(128,128,128)), + opacity_(1.0) +{} + +building_symbolizer::building_symbolizer(color const& fill, expression_ptr height) + : symbolizer_base(), + fill_(fill), + height_(height), + opacity_(1.0) {} + +color const& building_symbolizer::get_fill() const +{ + return fill_; +} + +void building_symbolizer::set_fill(color const& fill) +{ + fill_ = fill; +} +expression_ptr building_symbolizer::height() const +{ + return height_; +} + +void building_symbolizer::set_height(expression_ptr height) +{ + height_=height; +} + +void building_symbolizer::set_opacity(double opacity) +{ + opacity_ = opacity; +} + +double building_symbolizer::get_opacity() const +{ + return opacity_; +} + +} diff --git a/src/cairo_renderer.cpp b/src/cairo_renderer.cpp index 9be77f314..c26509bf3 100644 --- a/src/cairo_renderer.cpp +++ b/src/cairo_renderer.cpp @@ -1183,8 +1183,8 @@ void cairo_renderer_base::process(raster_symbolizer const& sym, // If there's a colorizer defined, use it to color the raster in-place raster_colorizer_ptr colorizer = sym.get_colorizer(); if (colorizer) - colorizer->colorize(source,feature.props()); - + colorizer->colorize(source,feature); + box2d target_ext = box2d(source->ext_); prj_trans.backward(target_ext, PROJ_ENVELOPE_POINTS); diff --git a/src/feature_kv_iterator.cpp b/src/feature_kv_iterator.cpp new file mode 100644 index 000000000..00af9a54c --- /dev/null +++ b/src/feature_kv_iterator.cpp @@ -0,0 +1,51 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2012 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ + +#include +#include + +namespace mapnik { + + +feature_kv_iterator::feature_kv_iterator (feature_impl const& f, bool begin) + : f_(f), + itr_( begin ? f_.ctx_->begin() : f_.ctx_->end()) {} + + +void feature_kv_iterator::increment() +{ + ++itr_; +} + +bool feature_kv_iterator::equal( feature_kv_iterator const& other) const +{ + return ( itr_ == other.itr_); +} + +feature_kv_iterator::value_type const& feature_kv_iterator::dereference() const +{ + boost::get<0>(kv_) = itr_->first; + boost::get<1>(kv_) = f_.get(itr_->first); + return kv_; +} + +} // endof mapnik namespace diff --git a/src/feature_style_processor.cpp b/src/feature_style_processor.cpp index f2204cba8..d63222b67 100644 --- a/src/feature_style_processor.cpp +++ b/src/feature_style_processor.cpp @@ -359,7 +359,7 @@ void feature_style_processor::apply_to_layer(layer const& lay, Proces while ((feature = features->next())) { - if (prev && prev->props()[group_by] != feature->props()[group_by]) + if (prev && prev->get(group_by) != feature->get(group_by)) { // We're at a value boundary, so render what we have // up to this point. diff --git a/src/memory_datasource.cpp b/src/memory_datasource.cpp index 7d142c06a..d5e42f892 100644 --- a/src/memory_datasource.cpp +++ b/src/memory_datasource.cpp @@ -118,18 +118,4 @@ void memory_datasource::clear() features_.clear(); } -// point_datasource - -void point_datasource::add_point(double x, double y, const char* key, const char* value) -{ - feature_ptr feature(feature_factory::create(feature_id_)); - ++feature_id_; - geometry_type * pt = new geometry_type(mapnik::Point); - pt->move_to(x,y); - feature->add_geometry(pt); - transcoder tr("utf-8"); - (*feature)[key] = tr.transcode(value); - this->push(feature); -} - } diff --git a/src/metawriter.cpp b/src/metawriter.cpp index a97fcb6a5..02cd62e65 100644 --- a/src/metawriter.cpp +++ b/src/metawriter.cpp @@ -105,24 +105,23 @@ void metawriter_json_stream::write_properties(Feature const& feature, metawriter { *f_ << "}," << //Close coordinates object "\n \"properties\": {"; - std::map const &fprops = feature.props(); + int i = 0; - BOOST_FOREACH(std::string p, properties) + BOOST_FOREACH(std::string const& p, properties) { - std::map::const_iterator itr = fprops.find(p); - std::string text; - if (itr != fprops.end()) + if (feature.has_key(p)) { - // Skip empty props - if(itr->second.to_string().size() == 0) continue; // ignore empty + mapnik::value const& val = feature.get(p); + std::string str = val.to_string(); + if (str.size() == 0) continue; // ignore empty attributes //Property found - text = boost::replace_all_copy(boost::replace_all_copy(itr->second.to_string(), "\\", "\\\\"), "\"", "\\\""); + std::string text = boost::replace_all_copy(boost::replace_all_copy(str, "\\", "\\\\"), "\"", "\\\""); if (i++) *f_ << ","; *f_ << "\n \"" << p << "\":\"" << text << "\""; } } - + *f_ << "\n} }"; } @@ -330,8 +329,7 @@ metawriter_json::metawriter_json(metawriter_properties dflt_properties, path_exp void metawriter_json::start(metawriter_property_map const& properties) { - filename_ = - path_processor::evaluate(*fn_, properties); + filename_ = path_processor::evaluate(*fn_, properties); #ifdef MAPNIK_DEBUG std::clog << "Metawriter JSON: filename=" << filename_ << "\n"; #endif diff --git a/src/metawriter_inmem.cpp b/src/metawriter_inmem.cpp index be7617c13..12cec9573 100644 --- a/src/metawriter_inmem.cpp +++ b/src/metawriter_inmem.cpp @@ -38,25 +38,22 @@ using mapnik::Feature; using mapnik::metawriter_properties; // intersect a set of properties with those in the feature descriptor -map intersect_properties(const Feature &feature, const metawriter_properties &properties) { - const map &fprops = feature.props(); - map nprops; +map intersect_properties(Feature const& feature, metawriter_properties const& properties) { - BOOST_FOREACH(string p, properties) { - map::const_iterator itr = fprops.find(p); - if (itr != fprops.end()) { - nprops.insert(*itr); + map nprops; + BOOST_FOREACH(string p, properties) + { + if (feature.has_key(p)) + nprops.insert(std::make_pair(p,feature.get(p))); } - } - - return nprops; -} -} // end anonymous namespace + + return nprops; +}} // end anonymous namespace namespace mapnik { metawriter_inmem::metawriter_inmem(metawriter_properties dflt_properties) - : metawriter(dflt_properties) { + : metawriter(dflt_properties) { } metawriter_inmem::~metawriter_inmem() { @@ -66,10 +63,10 @@ void metawriter_inmem::add_box(box2d const& box, Feature const& feature, CoordTransform const& /*t*/, metawriter_properties const& properties) { - meta_instance inst; - inst.box = box; - inst.properties = intersect_properties(feature, properties); - instances_.push_back(inst); + meta_instance inst; + inst.box = box; + inst.properties = intersect_properties(feature, properties); + instances_.push_back(inst); } void @@ -78,12 +75,12 @@ metawriter_inmem::add_text(text_placement_info const& p, Feature const& feature, CoordTransform const& /*t*/, metawriter_properties const& properties) { - if (p.extents.valid()) { - meta_instance inst; - inst.properties = intersect_properties(feature, properties); - inst.box = p.extents; - instances_.push_back(inst); - } + if (p.extents.valid()) { + meta_instance inst; + inst.properties = intersect_properties(feature, properties); + inst.box = p.extents; + instances_.push_back(inst); + } } void @@ -91,7 +88,7 @@ metawriter_inmem::add_polygon(path_type & path, Feature const& feature, CoordTransform const& t, metawriter_properties const& properties) { - add_vertices(path, feature, t, properties); + add_vertices(path, feature, t, properties); } void @@ -99,7 +96,7 @@ metawriter_inmem::add_line(path_type & path, Feature const& feature, CoordTransform const& t, metawriter_properties const& properties) { - add_vertices(path, feature, t, properties); + add_vertices(path, feature, t, properties); } void @@ -107,41 +104,41 @@ metawriter_inmem::add_vertices(path_type & path, Feature const& feature, CoordTransform const& /*t*/, metawriter_properties const& properties) { - box2d box; - unsigned cmd; - double x = 0.0, y = 0.0; + box2d box; + unsigned cmd; + double x = 0.0, y = 0.0; - path.rewind(0); - while ((cmd = path.vertex(&x, &y)) != SEG_END) { - box.expand_to_include(x, y); - } + path.rewind(0); + while ((cmd = path.vertex(&x, &y)) != SEG_END) { + box.expand_to_include(x, y); + } - if ((box.width() >= 0.0) && (box.height() >= 0.0)) { - meta_instance inst; - inst.properties = intersect_properties(feature, properties); - inst.box = box; - instances_.push_back(inst); - } + if ((box.width() >= 0.0) && (box.height() >= 0.0)) { + meta_instance inst; + inst.properties = intersect_properties(feature, properties); + inst.box = box; + instances_.push_back(inst); + } } void metawriter_inmem::start(metawriter_property_map const& /*properties*/) { - instances_.clear(); + instances_.clear(); } const std::list & metawriter_inmem::instances() const { - return instances_; + return instances_; } metawriter_inmem::meta_instance_list::const_iterator metawriter_inmem::inst_begin() const { - return instances_.begin(); + return instances_.begin(); } metawriter_inmem::meta_instance_list::const_iterator metawriter_inmem::inst_end() const { - return instances_.end(); + return instances_.end(); } diff --git a/src/polygon_symbolizer.cpp b/src/polygon_symbolizer.cpp index 380473d7b..5d7c3b81c 100644 --- a/src/polygon_symbolizer.cpp +++ b/src/polygon_symbolizer.cpp @@ -27,5 +27,58 @@ namespace mapnik { +polygon_symbolizer::polygon_symbolizer() + : symbolizer_base(), + fill_(color(128,128,128)), + opacity_(1.0), + gamma_(1.0), + gamma_method_(GAMMA_POWER) {} + +polygon_symbolizer::polygon_symbolizer(color const& fill) + : symbolizer_base(), + fill_(fill), + opacity_(1.0), + gamma_(1.0), + gamma_method_(GAMMA_POWER) {} + +color const& polygon_symbolizer::get_fill() const +{ + return fill_; } +void polygon_symbolizer::set_fill(color const& fill) +{ + fill_ = fill; +} + +void polygon_symbolizer::set_opacity(double opacity) +{ + opacity_ = opacity; +} + +double polygon_symbolizer::get_opacity() const +{ + return opacity_; +} + +void polygon_symbolizer::set_gamma(double gamma) +{ + gamma_ = gamma; +} + +double polygon_symbolizer::get_gamma() const +{ + return gamma_; +} + +void polygon_symbolizer::set_gamma_method(gamma_method_e gamma_method) +{ + gamma_method_ = gamma_method; +} + +gamma_method_e polygon_symbolizer::get_gamma_method() const +{ + return gamma_method_; +} + +} diff --git a/src/raster_colorizer.cpp b/src/raster_colorizer.cpp index 554592246..ea6682139 100644 --- a/src/raster_colorizer.cpp +++ b/src/raster_colorizer.cpp @@ -40,8 +40,10 @@ static const char *colorizer_mode_strings[] = { IMPLEMENT_ENUM( colorizer_mode, colorizer_mode_strings ) -colorizer_stop::colorizer_stop(const float value/* = 0*/, const colorizer_mode mode/* = COLORIZER_INHERIT*/, const color& _color/* = color(0,0,0,0)*/, const std::string& label/* ) ""*/) - : value_(value) +colorizer_stop::colorizer_stop(float value, colorizer_mode mode, + color const& _color, + std::string const& label) +: value_(value) , mode_(mode) , color_(_color) , label_(label) @@ -49,7 +51,7 @@ colorizer_stop::colorizer_stop(const float value/* = 0*/, const colorizer_mode m } -colorizer_stop::colorizer_stop(const colorizer_stop& stop) +colorizer_stop::colorizer_stop(colorizer_stop const& stop) : value_(stop.value_) , mode_(stop.mode_) , color_(stop.color_) @@ -67,9 +69,9 @@ colorizer_stop::~colorizer_stop() bool colorizer_stop::operator==(colorizer_stop const& other) const { return (value_ == other.value_) && - (color_ == other.color_) && - (mode_ == other.mode_) && - (label_ == other.label_); + (color_ == other.color_) && + (mode_ == other.mode_) && + (label_ == other.label_); } @@ -84,7 +86,7 @@ std::string colorizer_stop::to_string() const -raster_colorizer::raster_colorizer(colorizer_mode mode/* = COLORIZER_LINEAR*/, const color& _color/* = color(0,0,0,0)*/) +raster_colorizer::raster_colorizer(colorizer_mode mode, color const& _color) : default_mode_(mode) , default_color_(_color) , epsilon_(std::numeric_limits::epsilon()) @@ -96,10 +98,13 @@ raster_colorizer::~raster_colorizer() { } -bool raster_colorizer::add_stop(const colorizer_stop & stop) { +bool raster_colorizer::add_stop(colorizer_stop const& stop) +{ //make sure stops are added in order of value - if(stops_.size()) { - if(stop.get_value() <= stops_.back().get_value()) { + if(stops_.size()) + { + if(stop.get_value() <= stops_.back().get_value()) + { return false; } } @@ -109,7 +114,7 @@ bool raster_colorizer::add_stop(const colorizer_stop & stop) { return true; } -void raster_colorizer::colorize(raster_ptr const& raster,const std::map &Props) const +void raster_colorizer::colorize(raster_ptr const& raster, Feature const& f) const { unsigned *imageData = raster->data_.getData(); @@ -118,11 +123,11 @@ void raster_colorizer::colorize(raster_ptr const& raster,const std::map::const_iterator fi = Props.find("NODATA"); - if (fi != Props.end()) + //std::map::const_iterator fi = Props.find("NODATA"); + if (f.has_key("NODATA")) { hasNoData = true; - noDataValue = static_cast(fi->second.to_double()); + noDataValue = static_cast(f.get("NODATA").to_double()); } for (int i=0; i(fraction * ((float)end - (float)start) + start); } -color raster_colorizer::get_color(float value) const { +color raster_colorizer::get_color(float value) const +{ int stopCount = stops_.size(); //use default color if no stops - if(stopCount == 0) { + if(stopCount == 0) + { return default_color_; } @@ -153,31 +160,41 @@ color raster_colorizer::get_color(float value) const { int stopIdx = -1; bool foundStopIdx = false; - for(int i=0; i= stopCount) { //there is no next stop + if(nextStopIdx >= stopCount) + { + //there is no next stop nextStopIdx = stopCount - 1; } //3 - Work out the mode colorizer_mode stopMode; - if( stopIdx == -1 ) { //before the first stop + if( stopIdx == -1 ) + { + //before the first stop stopMode = default_mode_; } - else { + else + { stopMode = stops_[stopIdx].get_mode(); - if(stopMode == COLORIZER_INHERIT) { + if(stopMode == COLORIZER_INHERIT) + { stopMode = default_mode_; } } @@ -188,69 +205,76 @@ color raster_colorizer::get_color(float value) const { float stopValue = 0; float nextStopValue = 0; color outputColor = get_default_color(); - if(stopIdx == -1) { + if(stopIdx == -1) + { stopColor = default_color_; nextStopColor = stops_[nextStopIdx].get_color(); stopValue = value; nextStopValue = stops_[nextStopIdx].get_value(); } - else { + else + { stopColor = stops_[stopIdx].get_color(); nextStopColor = stops_[nextStopIdx].get_color(); stopValue = stops_[stopIdx].get_value(); nextStopValue = stops_[nextStopIdx].get_value(); } - switch(stopMode) { + switch(stopMode) + { case COLORIZER_LINEAR: + { + //deal with this separately so we don't have to worry about div0 + if(nextStopValue == stopValue) { - //deal with this separately so we don't have to worry about div0 - if(nextStopValue == stopValue) { - outputColor = stopColor; - } - else { - float fraction = (value - stopValue) / (nextStopValue - stopValue); - - unsigned r = interpolate(stopColor.red(), nextStopColor.red(),fraction); - unsigned g = interpolate(stopColor.green(), nextStopColor.green(),fraction); - unsigned b = interpolate(stopColor.blue(), nextStopColor.blue(),fraction); - unsigned a = interpolate(stopColor.alpha(), nextStopColor.alpha(),fraction); - - outputColor.set_red(r); - outputColor.set_green(g); - outputColor.set_blue(b); - outputColor.set_alpha(a); - } - + outputColor = stopColor; } - break; + else + { + float fraction = (value - stopValue) / (nextStopValue - stopValue); + + unsigned r = interpolate(stopColor.red(), nextStopColor.red(),fraction); + unsigned g = interpolate(stopColor.green(), nextStopColor.green(),fraction); + unsigned b = interpolate(stopColor.blue(), nextStopColor.blue(),fraction); + unsigned a = interpolate(stopColor.alpha(), nextStopColor.alpha(),fraction); + + outputColor.set_red(r); + outputColor.set_green(g); + outputColor.set_blue(b); + outputColor.set_alpha(a); + } + + } + break; case COLORIZER_DISCRETE: outputColor = stopColor; break; case COLORIZER_EXACT: default: //approximately equal (within epsilon) - if(fabs(value - stopValue) < epsilon_) { + if(fabs(value - stopValue) < epsilon_) + { outputColor = stopColor; } - else { + else + { outputColor = default_color_; } break; } - + /* - std::clog << "get_color: " << value << "\n"; - std::clog << "\tstopIdx: " << stopIdx << "\n"; - std::clog << "\tnextStopIdx: " << nextStopIdx << "\n"; - std::clog << "\tstopValue: " << stopValue << "\n"; - std::clog << "\tnextStopValue: " << nextStopValue << "\n"; - std::clog << "\tstopColor: " << stopColor.to_string() << "\n"; - std::clog << "\tnextStopColor: " << nextStopColor.to_string() << "\n"; - std::clog << "\tstopMode: " << stopMode.as_string() << "\n"; - std::clog << "\toutputColor: " << outputColor.to_string() << "\n"; -*/ + std::clog << "get_color: " << value << "\n"; + std::clog << "\tstopIdx: " << stopIdx << "\n"; + std::clog << "\tnextStopIdx: " << nextStopIdx << "\n"; + std::clog << "\tstopValue: " << stopValue << "\n"; + std::clog << "\tnextStopValue: " << nextStopValue << "\n"; + std::clog << "\tstopColor: " << stopColor.to_string() << "\n"; + std::clog << "\tnextStopColor: " << nextStopColor.to_string() << "\n"; + std::clog << "\tstopMode: " << stopMode.as_string() << "\n"; + std::clog << "\toutputColor: " << outputColor.to_string() << "\n"; + */ return outputColor; } diff --git a/src/symbolizer_helpers.cpp b/src/symbolizer_helpers.cpp index a71811d25..b786cc793 100644 --- a/src/symbolizer_helpers.cpp +++ b/src/symbolizer_helpers.cpp @@ -81,10 +81,21 @@ text_placement_info_ptr text_symbolizer_helper::get_poi return text_placement_info_ptr(); } +struct largest_bbox_first +{ + bool operator() (geometry_type const* g0, geometry_type const* g1) const + { + box2d b0 = g0->envelope(); + box2d b1 = g1->envelope(); + return b0.width()*b0.height() > b1.width()*b1.height(); + } + +}; template void text_symbolizer_helper::initialize_geometries() { + bool largest_box_only = false; unsigned num_geom = feature_.num_geometries(); for (unsigned i=0; i::initialize_geometries() // don't bother with empty geometries if (geom.num_points() == 0) continue; - - if ((geom.type() == Polygon) && sym_.get_minimum_path_length() > 0) + eGeomType type = geom.type(); + if (type == Polygon) { - // TODO - find less costly method than fetching full envelope - box2d gbox = t_.forward(geom.envelope(), prj_trans_); - if (gbox.width() < sym_.get_minimum_path_length()) + largest_box_only = true; + if (sym_.get_minimum_path_length() > 0) { - continue; + // TODO - find less costly method than fetching full envelope + box2d gbox = t_.forward(geom.envelope(), prj_trans_); + + if (gbox.width() < sym_.get_minimum_path_length()) + { + continue; + } } } // TODO - calculate length here as well geometries_to_process_.push_back(const_cast(&geom)); } + + if (largest_box_only) + { + geometries_to_process_.sort(largest_bbox_first()); + geo_itr_ = geometries_to_process_.begin(); + geometries_to_process_.erase(++geo_itr_,geometries_to_process_.end()); + } geo_itr_ = geometries_to_process_.begin(); } diff --git a/tests/python_tests/feature_id_test.py b/tests/python_tests/feature_id_test.py index e6206bb5b..2cfa244d3 100644 --- a/tests/python_tests/feature_id_test.py +++ b/tests/python_tests/feature_id_test.py @@ -32,10 +32,8 @@ def compare_shape_between_mapnik_and_ogr(shapefile,query=None): #import pdb;pdb.set_trace() eq_(feat1.id(),feat2.id(), '%s : ogr feature id %s "%s" does not equal shapefile feature id %s "%s"' - % (count,feat1.id(),str(feat1.attributes), feat2.id(),str(feat2.attributes)) ) - + % (count,feat1.id(),str(feat1.attributes), feat2.id(),str(feat2.attributes))) return True - def test_shapefile_line_featureset_id(): diff --git a/tests/python_tests/feature_test.py b/tests/python_tests/feature_test.py index ab6b35d1b..43ff7d581 100644 --- a/tests/python_tests/feature_test.py +++ b/tests/python_tests/feature_test.py @@ -6,71 +6,50 @@ from nose.tools import * import mapnik from binascii import unhexlify -class FeatureTest(unittest.TestCase): - def makeOne(self, *args, **kw): - return mapnik.Feature(*args, **kw) - - def test_default_constructor(self): - f = self.makeOne(1) - self.failUnless(f is not None) +def test_default_constructor(): + f = mapnik.Feature(mapnik.Context(),1) + eq_(f is not None,True) - def test_python_extended_constructor(self): - f = self.makeOne(1, 'POLYGON ((35 10, 10 20, 15 40, 45 45, 35 10),(20 30, 35 35, 30 20, 20 30))', foo="bar") - self.failUnlessEqual(f['foo'], 'bar') - self.failUnlessEqual(f.envelope(),mapnik.Box2d(10.0,10.0,45.0,45.0)) - - def test_set_get_properties(self): - f = self.makeOne(1) - counter = itertools.count(0) - def test_val(expected): - key = 'prop%d'%counter.next() - try: - f[key] = expected - except TypeError: - self.fail("%r (%s)"%(expected, type(expected))) - self.failUnlessEqual(f[key], expected) - for v in (1, True, 1.4, "foo", u"avión"): - test_val(v) - - def test_add_wkt_geometry(self): - def add_geom_wkt(wkt): - f = self.makeOne(1) - self.failUnlessEqual(len(f.geometries()), 0) - f.add_geometries_from_wkt(wkt) - self.failUnlessEqual(len(f.geometries()), 3) - e = mapnik.Box2d() - self.failUnlessEqual(e.valid(), False) - for g in f.geometries(): - if not e.valid(): - e = g.envelope() - else: - e +=g.envelope() - - self.failUnlessEqual(e, f.envelope()) - - def add_geom_wkb(wkb): - f = self.makeOne(1) - self.failUnlessEqual(len(f.geometries()), 0) - f.add_geometries_from_wkb(unhexlify(wkb)) - self.failUnlessEqual(len(f.geometries()), 1) - e = mapnik.Box2d() - self.failUnlessEqual(e.valid(), False) - for g in f.geometries(): - if not e.valid(): - e = g.envelope() - else: - e +=g.envelope() - - self.failUnlessEqual(e, f.envelope()) - - def run() : - add_geom_wkt('GEOMETRYCOLLECTION(POINT(4 6),LINESTRING(4 6,7 10),POLYGON ((30 10, 10 20, 20 40, 40 40, 30 10)))') - add_geom_wkb('010300000001000000050000000000000000003e4000000000000024400000000000002440000000000000344000000000000034400000000000004440000000000000444000000000000044400000000000003e400000000000002440') # POLYGON ((30 10, 10 20, 20 40, 40 40, 30 10)) - run() +def test_python_extended_constructor(): + context = mapnik.Context() + context.push('foo') + context.push('foo') + f = mapnik.Feature(context,1) + wkt = 'POLYGON ((35 10, 10 20, 15 40, 45 45, 35 10),(20 30, 35 35, 30 20, 20 30))' + f.add_geometries_from_wkt(wkt) + f['foo'] = 'bar' + eq_(f['foo'], 'bar') + eq_(f.envelope(),mapnik.Box2d(10.0,10.0,45.0,45.0)) + # reset + f['foo'] = u"avión" + eq_(f['foo'], u"avión") + f['foo'] = 1.4 + eq_(f['foo'], 1.4) + f['foo'] = True + eq_(f['foo'], True) +def test_add_geom_wkb(): +# POLYGON ((30 10, 10 20, 20 40, 40 40, 30 10)) + wkb = '010300000001000000050000000000000000003e4000000000000024400000000000002440000000000000344000000000000034400000000000004440000000000000444000000000000044400000000000003e400000000000002440' + context = mapnik.Context() + f = mapnik.Feature(context,1) + eq_(len(f.geometries()), 0) + f.add_geometries_from_wkb(unhexlify(wkb)) + eq_(len(f.geometries()), 1) + e = mapnik.Box2d() + eq_(e.valid(), False) + for g in f.geometries(): + if not e.valid(): + e = g.envelope() + else: + e +=g.envelope() + + eq_(e, f.envelope()) def test_feature_expression_evaluation(): - f = mapnik.Feature(1) + context = mapnik.Context() + context.push('name') + f = mapnik.Feature(context,1) f['name'] = 'a' eq_(f['name'],u'a') expr = mapnik.Expression("[name]='a'") @@ -82,7 +61,9 @@ def test_feature_expression_evaluation(): # https://github.com/mapnik/mapnik/issues/933 def test_feature_expression_evaluation_missing_attr(): - f = mapnik.Feature(1) + context = mapnik.Context() + context.push('name') + f = mapnik.Feature(context,1) f['name'] = u'a' eq_(f['name'],u'a') expr = mapnik.Expression("[fielddoesnotexist]='a'") @@ -94,7 +75,9 @@ def test_feature_expression_evaluation_missing_attr(): # https://github.com/mapnik/mapnik/issues/934 def test_feature_expression_evaluation_attr_with_spaces(): - f = mapnik.Feature(1) + context = mapnik.Context() + context.push('name with space') + f = mapnik.Feature(context,1) f['name with space'] = u'a' eq_(f['name with space'],u'a') expr = mapnik.Expression("[name with space]='a'") diff --git a/tests/python_tests/filter_test.py b/tests/python_tests/filter_test.py index d17f43652..aea7cf2fa 100644 --- a/tests/python_tests/filter_test.py +++ b/tests/python_tests/filter_test.py @@ -93,25 +93,33 @@ def test_filter_init(): def test_regex_match(): - f = mapnik.Feature(0) + context = mapnik.Context() + context.push('name') + f = mapnik.Feature(context,0) f["name"] = 'test' expr = mapnik.Expression("[name].match('test')") eq_(expr.evaluate(f),True) # 1 == True def test_unicode_regex_match(): - f = mapnik.Feature(0) + context = mapnik.Context() + context.push('name') + f = mapnik.Feature(context,0) f["name"] = 'Québec' expr = mapnik.Expression("[name].match('Québec')") eq_(expr.evaluate(f),True) # 1 == True def test_regex_replace(): - f = mapnik.Feature(0) + context = mapnik.Context() + context.push('name') + f = mapnik.Feature(context,0) f["name"] = 'test' expr = mapnik.Expression("[name].replace('(\B)|( )','$1 ')") eq_(expr.evaluate(f),'t e s t') def test_unicode_regex_replace(): - f = mapnik.Feature(0) + context = mapnik.Context() + context.push('name') + f = mapnik.Feature(context,0) f["name"] = 'Québec' expr = mapnik.Expression("[name].replace('(\B)|( )','$1 ')") eq_(expr.evaluate(f), u'Q u é b e c') diff --git a/tests/python_tests/geometry_io_test.py b/tests/python_tests/geometry_io_test.py index d937839df..b2bce104c 100644 --- a/tests/python_tests/geometry_io_test.py +++ b/tests/python_tests/geometry_io_test.py @@ -34,7 +34,7 @@ def compare_wkb_from_wkt(wkt,num=None): paths = mapnik.Path.from_wkt(wkt) # add geometry(s) to feature from wkt - f = mapnik.Feature(1) + f = mapnik.Feature(mapnik.Context(),1) f.add_geometries_from_wkt(wkt) # ensure both have same result @@ -65,7 +65,7 @@ def compare_wkt_from_wkt(wkt,num=None): paths = mapnik.Path.from_wkt(wkt) # add geometry(s) to feature from wkt - f = mapnik.Feature(1) + f = mapnik.Feature(mapnik.Context(),1) f.add_geometries_from_wkt(wkt) # compare to original, which may not have significant digits @@ -113,14 +113,14 @@ def test_geometry_index_error(): wkt = 'Point (0 0)' paths = mapnik.Path.from_wkt(wkt) paths[3] - f = mapnik.Feature(1) + f = mapnik.Feature(mapnik.Context(),1) f.add_geometries_from_wkt(wkt) f.geometries()[3] @raises(IndexError) def test_geometry_index_error2(): wkt = 'Point (0 0)' - f = mapnik.Feature(1) + f = mapnik.Feature(mapnik.Context(),1) f.add_geometries_from_wkt(wkt) f.geometries()[3] diff --git a/tests/python_tests/memory_datasource_test.py b/tests/python_tests/memory_datasource_test.py index 73b2575e3..4afce1046 100644 --- a/tests/python_tests/memory_datasource_test.py +++ b/tests/python_tests/memory_datasource_test.py @@ -1,40 +1,34 @@ #encoding: utf8 -import itertools -import unittest +import mapnik +from nose.tools import * -class MemoryDatasource(unittest.TestCase): - ids = itertools.count(0) +def test_add_feature(): + md = mapnik.MemoryDatasource() + eq_(md.num_features(), 0) + context = mapnik.Context() + context.push('foo') + feature = mapnik.Feature(context,1) + feature['foo'] = 'bar' + feature.add_geometries_from_wkt('POINT(2 3)') + md.add_feature(feature) + eq_(md.num_features(), 1) - def makeOne(self, *args, **kw): - from mapnik import MemoryDatasource - return MemoryDatasource(*args, **kw) + featureset = md.features_at_point(mapnik.Coord(2,3)) + retrieved = [] + feat = featureset.next() + while featureset.next(): + retrieved.append(feat) + + eq_(len(retrieved), 1) + f = retrieved[0] + eq_(f['foo'], 'bar') - def makeFeature(self, wkt, **properties): - from mapnik import Feature - f = Feature(self.ids.next()) - f.add_geometries_from_wkt(wkt) - for k,v in properties.iteritems(): - f[k] = v - return f - - def test_default_constructor(self): - f = self.makeOne() - self.failUnless(f is not None) - - def test_add_feature(self): - md = self.makeOne() - self.failUnlessEqual(md.num_features(), 0) - md.add_feature(self.makeFeature('Point(2 3)', foo='bar')) - self.failUnlessEqual(md.num_features(), 1) - - from mapnik import Coord - retrieved = md.features_at_point(Coord(2,3)).features - self.failUnlessEqual(len(retrieved), 1) - f = retrieved[0] - self.failUnlessEqual(f['foo'], 'bar') - - retrieved = md.features_at_point(Coord(20,30)).features - self.failUnlessEqual(len(retrieved), 0) + featureset = md.features_at_point(Coord(20,30)).features + retrieved = [] + feat = featureset.next() + while featureset.next(): + retrieved.append(feat) + eq_(len(retrieved), 0) if __name__ == "__main__": [eval(run)() for run in dir() if 'test_' in run] diff --git a/tests/python_tests/ogr_test.py b/tests/python_tests/ogr_test.py index 4cd7d0d5a..ade519fde 100644 --- a/tests/python_tests/ogr_test.py +++ b/tests/python_tests/ogr_test.py @@ -39,10 +39,6 @@ if 'ogr' in mapnik.DatasourceCache.instance().plugin_names(): eq_(f['NOM_FR'], u'Québec') eq_(f['Shape_Area'], 1512185733150.0) eq_(f['Shape_Leng'], 19218883.724300001) - - # Check that the deprecated interface still works, - # remove me once the deprecated code is cleaned up - eq_(f.properties['Shape_Leng'], 19218883.724300001) @raises(RuntimeError) def test_that_nonexistant_query_field_throws(**kwargs): diff --git a/tests/python_tests/render_grid_test.py b/tests/python_tests/render_grid_test.py index b490825f1..674319bb6 100644 --- a/tests/python_tests/render_grid_test.py +++ b/tests/python_tests/render_grid_test.py @@ -37,11 +37,28 @@ def resolve(grid,x,y): def create_grid_map(width,height): - places_ds = mapnik.PointDatasource() - places_ds.add_point(143.10,-38.60,'Name','South East') - places_ds.add_point(142.48,-38.60,'Name','South West') - places_ds.add_point(142.48,-38.38,'Name','North West') - places_ds.add_point(143.10,-38.38,'Name','North East') + ds = mapnik.MemoryDatasource() + context = mapnik.Context() + context.push('Name') + f = mapnik.Feature(context,1) + f['Name'] = 'South East' + f.add_geometries_from_wkt('POINT (143.10 -38.60)') + ds.add_feature(f) + + f = mapnik.Feature(context,2) + f['Name'] = 'South West' + f.add_geometries_from_wkt('POINT (142.48 -38.60)') + ds.add_feature(f) + + f = mapnik.Feature(context,3) + f['Name'] = 'North West' + f.add_geometries_from_wkt('POINT (142.48 -38.38)') + ds.add_feature(f) + + f = mapnik.Feature(context,4) + f['Name'] = 'North East' + f.add_geometries_from_wkt('POINT (143.10 -38.38)') + ds.add_feature(f) s = mapnik.Style() r = mapnik.Rule() #symb = mapnik.PointSymbolizer() @@ -59,7 +76,7 @@ def create_grid_map(width,height): s.rules.append(r) lyr = mapnik.Layer('Places') - lyr.datasource = places_ds + lyr.datasource = ds lyr.styles.append('places_labels') m = mapnik.Map(width,height) m.append_style('places_labels',s) diff --git a/tests/python_tests/render_test.py b/tests/python_tests/render_test.py index d2bca07a8..c1e15e2f0 100644 --- a/tests/python_tests/render_test.py +++ b/tests/python_tests/render_test.py @@ -120,29 +120,37 @@ def resolve(grid,x,y): def test_render_grid(): - places_ds = mapnik.PointDatasource() - places_ds.add_point(143.10,-38.60,'Name','South East') - places_ds.add_point(142.48,-38.60,'Name','South West') - places_ds.add_point(142.48,-38.38,'Name','North West') - places_ds.add_point(143.10,-38.38,'Name','North East') + ds = mapnik.MemoryDatasource() + context = mapnik.Context() + context.push('Name') + f = mapnik.Feature(context,1) + f['Name'] = 'South East' + f.add_geometries_from_wkt('POINT (143.10 -38.60)') + ds.add_feature(f) + + f = mapnik.Feature(context,2) + f['Name'] = 'South West' + f.add_geometries_from_wkt('POINT (142.48 -38.60)') + ds.add_feature(f) + + f = mapnik.Feature(context,3) + f['Name'] = 'North West' + f.add_geometries_from_wkt('POINT (142.48 -38.38)') + ds.add_feature(f) + + f = mapnik.Feature(context,4) + f['Name'] = 'North East' + f.add_geometries_from_wkt('POINT (143.10 -38.38)') + ds.add_feature(f) + s = mapnik.Style() r = mapnik.Rule() - #symb = mapnik.PointSymbolizer() symb = mapnik.MarkersSymbolizer() symb.allow_overlap = True r.symbols.append(symb) - label = mapnik.TextSymbolizer(mapnik.Expression('[Name]'), - 'DejaVu Sans Book', - 10, - mapnik.Color('black') - ) - label.allow_overlap = True - label.displacement = (0,-10) - #r.symbols.append(label) - s.rules.append(r) lyr = mapnik.Layer('Places') - lyr.datasource = places_ds + lyr.datasource = ds lyr.styles.append('places_labels') m = mapnik.Map(256,256) m.append_style('places_labels',s) @@ -184,9 +192,19 @@ def test_render_points(): if not mapnik.has_cairo(): return # create and populate point datasource (WGS84 lat-lon coordinates) - places_ds = mapnik.PointDatasource() - places_ds.add_point(142.48,-38.38,'Name','Westernmost Point') # westernmost - places_ds.add_point(143.10,-38.60,'Name','Southernmost Point') # southernmost + ds = mapnik.MemoryDatasource() + context = mapnik.Context() + context.push('Name') + f = mapnik.Feature(context,1) + f['Name'] = 'Westernmost Point' + f.add_geometries_from_wkt('POINT (142.48 -38.38)') + ds.add_feature(f) + + f = mapnik.Feature(context,2) + f['Name'] = 'Southernmost Point' + f.add_geometries_from_wkt('POINT (143.10,-38.60)') + ds.add_feature(f) + # create layer/rule/style s = mapnik.Style() r = mapnik.Rule() @@ -195,7 +213,7 @@ def test_render_points(): r.symbols.append(symb) s.rules.append(r) lyr = mapnik.Layer('Places','+proj=latlon +datum=WGS84') - lyr.datasource = places_ds + lyr.datasource = ds lyr.styles.append('places_labels') # latlon bounding box corners ul_lonlat = mapnik.Coord(142.30,-38.20) @@ -216,7 +234,7 @@ def test_render_points(): # Render to SVG so that it can be checked how many points are there with string comparison svg_file = os.path.join(tempfile.gettempdir(),'%s.svg') mapnik.render_to_file(m, svg_file) - num_points_present = len(places_ds.all_features()) + num_points_present = len(ds.all_features()) svg = open(svg_file,'r').read() num_points_rendered = svg.count(' + + + + + My Style + + shape + points.shp + + + + + + diff --git a/utils/pgsql2sqlite/build.py b/utils/pgsql2sqlite/build.py index 32c666adb..c342fefb2 100644 --- a/utils/pgsql2sqlite/build.py +++ b/utils/pgsql2sqlite/build.py @@ -40,7 +40,7 @@ headers = ['#plugins/input/postgis'] + env['CPPPATH'] libraries = [] boost_program_options = 'boost_program_options%s' % env['BOOST_APPEND'] -libraries.extend([boost_program_options,'sqlite3','pq','mapnik']) +libraries.extend([boost_program_options,'sqlite3','pq','mapnik','icuuc']) linkflags = env['CUSTOM_LDFLAGS'] if env['SQLITE_LINKFLAGS']: diff --git a/utils/pgsql2sqlite/pgsql2sqlite.hpp b/utils/pgsql2sqlite/pgsql2sqlite.hpp index 1de81ae8c..8cd7270ca 100644 --- a/utils/pgsql2sqlite/pgsql2sqlite.hpp +++ b/utils/pgsql2sqlite/pgsql2sqlite.hpp @@ -141,9 +141,14 @@ void pgsql2sqlite(Connection conn, int geometry_oid = -1; std::string output_table_insert_sql = "insert into " + output_table_name + " values (?"; + + context_ptr ctx = boost::make_shared(); for ( unsigned pos = 0; pos < num_fields ; ++pos) { + const char* field_name = cursor->getFieldName(pos); + ctx->push(field_name); + if (pos > 0) { create_sql << ","; @@ -216,7 +221,7 @@ void pgsql2sqlite(Connection conn, sqlite::record_type output_rec; output_rec.push_back(sqlite::value_type(pkid)); bool empty_geom = true; - const char * buf = 0; + const char * buf = 0; for (unsigned pos=0 ; pos < num_fields; ++pos) { if (! cursor->isNull(pos)) @@ -275,7 +280,7 @@ void pgsql2sqlite(Connection conn, { if (oid == geometry_oid) { - mapnik::Feature feat(pkid); + mapnik::Feature feat(ctx,pkid); geometry_utils::from_wkb(feat.paths(),buf,size,wkbGeneric); if (feat.num_geometries() > 0) {