Merge pull request #1021 from mapnik/geometry_type_descriptor

Add Geometry type descriptor
This commit is contained in:
Artem Pavlenko 2012-01-17 11:31:24 -08:00
commit 9407991be4
47 changed files with 4919 additions and 160 deletions

View file

@ -233,9 +233,6 @@ class _Projection(Projection,_injector):
class _Datasource(Datasource,_injector): class _Datasource(Datasource,_injector):
def describe(self):
return Describe(self)
def all_features(self,fields=None): def all_features(self,fields=None):
query = Query(self.envelope()) query = Query(self.envelope())
attributes = fields or self.fields() attributes = fields or self.fields()
@ -710,7 +707,6 @@ __all__ = [
'SQLite', 'SQLite',
'Osm', 'Osm',
'Kismet', 'Kismet',
'Describe',
# version and environment # version and environment
'mapnik_version_string', 'mapnik_version_string',
'mapnik_version', 'mapnik_version',

View file

@ -82,30 +82,15 @@ boost::shared_ptr<mapnik::datasource> create_datasource(const dict& d)
return mapnik::datasource_cache::create(params, bind); return mapnik::datasource_cache::create(params, bind);
} }
std::string describe(boost::shared_ptr<mapnik::datasource> const& ds) boost::python::dict describe(boost::shared_ptr<mapnik::datasource> const& ds)
{ {
std::stringstream ss; boost::python::dict description;
if (ds) mapnik::layer_descriptor ld = ds->get_descriptor();
{ description["type"] = ds->type();
ss << ds->get_descriptor() << "\n"; description["name"] = ld.get_name();
} description["geometry_type"] = ds->get_geometry_type();
else description["encoding"] = ld.get_encoding();
{ return description;
ss << "Null\n";
}
return ss.str();
}
std::string encoding(boost::shared_ptr<mapnik::datasource> const& ds)
{
layer_descriptor ld = ds->get_descriptor();
return ld.get_encoding();
}
std::string name(boost::shared_ptr<mapnik::datasource> const& ds)
{
layer_descriptor ld = ds->get_descriptor();
return ld.get_name();
} }
boost::python::list fields(boost::shared_ptr<mapnik::datasource> const& ds) boost::python::list fields(boost::shared_ptr<mapnik::datasource> const& ds)
@ -163,23 +148,34 @@ void export_datasource()
{ {
using namespace boost::python; using namespace boost::python;
enum_<mapnik::datasource::datasource_t>("DataType")
.value("Vector",mapnik::datasource::Vector)
.value("Raster",mapnik::datasource::Raster)
;
enum_<mapnik::datasource::geometry_t>("DataGeometryType")
.value("Point",mapnik::datasource::Point)
.value("LineString",mapnik::datasource::LineString)
.value("Polygon",mapnik::datasource::Polygon)
.value("Collection",mapnik::datasource::Collection)
;
class_<datasource,boost::shared_ptr<datasource>, class_<datasource,boost::shared_ptr<datasource>,
boost::noncopyable>("Datasource",no_init) boost::noncopyable>("Datasource",no_init)
.def("type",&datasource::type)
.def("geometry_type",&datasource::get_geometry_type)
.def("describe",&describe)
.def("envelope",&datasource::envelope) .def("envelope",&datasource::envelope)
.def("descriptor",&datasource::get_descriptor) //todo
.def("features",&datasource::features) .def("features",&datasource::features)
.def("bind",&datasource::bind) .def("bind",&datasource::bind)
.def("fields",&fields) .def("fields",&fields)
.def("field_types",&field_types) .def("field_types",&field_types)
.def("encoding",&encoding) //todo expose as property
.def("name",&name)
.def("features_at_point",&datasource::features_at_point) .def("features_at_point",&datasource::features_at_point)
.def("params",&datasource::params,return_value_policy<copy_const_reference>(), .def("params",&datasource::params,return_value_policy<copy_const_reference>(),
"The configuration parameters of the data source. " "The configuration parameters of the data source. "
"These vary depending on the type of data source.") "These vary depending on the type of data source.")
; ;
def("Describe",&describe);
def("CreateDatasource",&create_datasource); def("CreateDatasource",&create_datasource);
class_<point_datasource, bases<datasource>, boost::noncopyable>("PointDatasource", init<>()) class_<point_datasource, bases<datasource>, boost::noncopyable>("PointDatasource", init<>())

View file

@ -33,7 +33,6 @@
#include <mapnik/metawriter_inmem.hpp> #include <mapnik/metawriter_inmem.hpp>
#include <mapnik/util/deepcopy.hpp> #include <mapnik/util/deepcopy.hpp>
#include "mapnik_enumeration.hpp" #include "mapnik_enumeration.hpp"
#include "python_optional.hpp"
using mapnik::color; using mapnik::color;
using mapnik::coord; using mapnik::coord;
@ -213,8 +212,6 @@ void export_map()
.value("ADJUST_CANVAS_HEIGHT", mapnik::Map::ADJUST_CANVAS_HEIGHT) .value("ADJUST_CANVAS_HEIGHT", mapnik::Map::ADJUST_CANVAS_HEIGHT)
; ;
python_optional<mapnik::color> ();
python_optional<mapnik::box2d<double> > ();
class_<std::vector<layer> >("Layers") class_<std::vector<layer> >("Layers")
.def(vector_indexing_suite<std::vector<layer> >()) .def(vector_indexing_suite<std::vector<layer> >())
; ;

View file

@ -85,6 +85,7 @@ void export_label_collision_detector();
#include <mapnik/save_map.hpp> #include <mapnik/save_map.hpp>
#include "python_grid_utils.hpp" #include "python_grid_utils.hpp"
#include "mapnik_value_converter.hpp" #include "mapnik_value_converter.hpp"
#include "python_optional.hpp"
#if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO) #if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO)
#include <pycairo.h> #include <pycairo.h>
@ -630,6 +631,9 @@ BOOST_PYTHON_MODULE(_mapnik)
def("has_cairo", &has_cairo, "Get cairo library status"); def("has_cairo", &has_cairo, "Get cairo library status");
def("has_pycairo", &has_pycairo, "Get pycairo module status"); def("has_pycairo", &has_pycairo, "Get pycairo module status");
python_optional<mapnik::color> ();
python_optional<mapnik::box2d<double> > ();
python_optional<mapnik::datasource::geometry_t> ();
register_ptr_to_python<mapnik::expression_ptr>(); register_ptr_to_python<mapnik::expression_ptr>();
register_ptr_to_python<mapnik::path_expression_ptr>(); register_ptr_to_python<mapnik::path_expression_ptr>();
to_python_converter<mapnik::value_holder,mapnik_param_to_python>(); to_python_converter<mapnik::value_holder,mapnik_param_to_python>();

View file

@ -40,7 +40,7 @@
#include <string> #include <string>
namespace mapnik { namespace mapnik {
typedef MAPNIK_DECL boost::shared_ptr<Feature> feature_ptr; typedef MAPNIK_DECL boost::shared_ptr<Feature> feature_ptr;
struct MAPNIK_DECL Featureset struct MAPNIK_DECL Featureset
@ -68,12 +68,19 @@ public:
class MAPNIK_DECL datasource : private boost::noncopyable class MAPNIK_DECL datasource : private boost::noncopyable
{ {
public: public:
enum datasource_t { enum datasource_t {
Vector, Vector,
Raster Raster
}; };
enum geometry_t {
Point = 1,
LineString = 2,
Polygon = 3,
Collection = 4
};
datasource (parameters const& params) datasource (parameters const& params)
: params_(params), : params_(params),
is_bound_(false) is_bound_(false)
@ -95,7 +102,7 @@ public:
* @brief Get the type of the datasource * @brief Get the type of the datasource
* @return The type of the datasource (Vector or Raster) * @return The type of the datasource (Vector or Raster)
*/ */
virtual int type() const=0; virtual datasource_t type() const=0;
/*! /*!
* @brief Connect to the datasource * @brief Connect to the datasource
@ -105,6 +112,7 @@ public:
virtual featureset_ptr features(const query& q) const=0; virtual featureset_ptr features(const query& q) const=0;
virtual featureset_ptr features_at_point(coord2d const& pt) const=0; virtual featureset_ptr features_at_point(coord2d const& pt) const=0;
virtual box2d<double> envelope() const=0; virtual box2d<double> envelope() const=0;
virtual boost::optional<geometry_t> get_geometry_type() const=0;
virtual layer_descriptor get_descriptor() const=0; virtual layer_descriptor get_descriptor() const=0;
virtual ~datasource() {}; virtual ~datasource() {};
protected: protected:

View file

@ -45,22 +45,22 @@ public:
: name_(other.name_), : name_(other.name_),
encoding_(other.encoding_), encoding_(other.encoding_),
desc_ar_(other.desc_ar_) {} desc_ar_(other.desc_ar_) {}
void set_name(std::string const& name) void set_name(std::string const& name)
{ {
name_=name; name_ = name;
} }
std::string const& get_name() const std::string const& get_name() const
{ {
return name_; return name_;
} }
void set_encoding(std::string const& encoding) void set_encoding(std::string const& encoding)
{ {
encoding_=encoding; encoding_ = encoding;
} }
std::string const& get_encoding() const std::string const& get_encoding() const
{ {
return encoding_; return encoding_;
@ -70,12 +70,12 @@ public:
{ {
desc_ar_.push_back(desc); desc_ar_.push_back(desc);
} }
std::vector<attribute_descriptor> const& get_descriptors() const std::vector<attribute_descriptor> const& get_descriptors() const
{ {
return desc_ar_; return desc_ar_;
} }
std::vector<attribute_descriptor>& get_descriptors() std::vector<attribute_descriptor>& get_descriptors()
{ {
return desc_ar_; return desc_ar_;
@ -86,20 +86,19 @@ private:
std::string encoding_; std::string encoding_;
std::vector<attribute_descriptor> desc_ar_; std::vector<attribute_descriptor> desc_ar_;
}; };
template <typename charT,typename traits> template <typename charT,typename traits>
inline std::basic_ostream<charT,traits>& inline std::basic_ostream<charT,traits>&
operator << (std::basic_ostream<charT,traits>& out, operator << (std::basic_ostream<charT,traits>& out,
layer_descriptor const& ld) layer_descriptor const& ld)
{ {
out << "name=" << ld.get_name() << "\n"; out << "name: " << ld.get_name() << "\n";
out << "encoding=" << ld.get_encoding() << "\n"; out << "encoding: " << ld.get_encoding() << "\n";
std::vector<attribute_descriptor> const& desc_ar=ld.get_descriptors(); std::vector<attribute_descriptor> const& desc_ar = ld.get_descriptors();
std::vector<attribute_descriptor>::const_iterator pos=desc_ar.begin(); std::vector<attribute_descriptor>::const_iterator pos = desc_ar.begin();
while (pos != desc_ar.end()) while (pos != desc_ar.end())
{ {
out << *pos++ << "\n"; out << *pos++ << "\n";
} }
return out; return out;
} }

View file

@ -39,10 +39,11 @@ public:
memory_datasource(); memory_datasource();
virtual ~memory_datasource(); virtual ~memory_datasource();
void push(feature_ptr feature); void push(feature_ptr feature);
int type() const; datasource::datasource_t type() const;
featureset_ptr features(const query& q) const; featureset_ptr features(const query& q) const;
featureset_ptr features_at_point(coord2d const& pt) const; featureset_ptr features_at_point(coord2d const& pt) const;
box2d<double> envelope() const; box2d<double> envelope() const;
boost::optional<geometry_t> get_geometry_type() const;
layer_descriptor get_descriptor() const; layer_descriptor get_descriptor() const;
size_t size() const; size_t size() const;
void clear(); void clear();
@ -59,8 +60,7 @@ class MAPNIK_DECL point_datasource : public memory_datasource {
public: public:
point_datasource() : point_datasource() :
feature_id_(1) {} feature_id_(1) {}
void add_point(double x, double y, const char* key, const char* value); void add_point(double x, double y, const char* key, const char* value);
inline int type() const { return datasource::Vector; }
private: private:
int feature_id_; int feature_id_;

View file

@ -39,8 +39,8 @@
namespace mapnik namespace mapnik
{ {
typedef boost::variant<value_null,int,double,std::string> value_holder; typedef boost::variant<value_null,int,double,std::string> value_holder;
typedef std::pair<const std::string, value_holder> parameter; typedef std::pair<std::string, value_holder> parameter;
typedef std::map<const std::string, value_holder> param_map; typedef std::map<std::string, value_holder> param_map;
template <typename T> template <typename T>
struct value_extractor_visitor : public boost::static_visitor<> struct value_extractor_visitor : public boost::static_visitor<>

View file

@ -0,0 +1,66 @@
/*****************************************************************************
*
* 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
*
*****************************************************************************/
//$Id$
#ifndef MAPNIK_GEOMETRY_TO_DS_TYPE
#define MAPNIK_GEOMETRY_TO_DS_TYPE
// mapnik
#include <mapnik/global.hpp>
#include <mapnik/geometry.hpp>
#include <mapnik/datasource.hpp>
// boost
#include <boost/optional.hpp>
namespace mapnik { namespace util {
void to_ds_type(mapnik::geometry_container const& paths,
boost::optional<mapnik::datasource::geometry_t> & result)
{
if (paths.size() == 1)
{
result.reset(static_cast<mapnik::datasource::geometry_t>(paths.front().type()));
}
else if (paths.size() > 1)
{
int multi_type = 0;
geometry_container::const_iterator itr = paths.begin();
geometry_container::const_iterator end = paths.end();
for ( ; itr!=end; ++itr)
{
int type = static_cast<int>(itr->type());
if (multi_type > 0 && multi_type != type)
{
result.reset(datasource::Collection);
}
multi_type = type;
result.reset(static_cast<mapnik::datasource::geometry_t>(type));
}
}
}
}}
#endif // MAPNIK_GEOMETRY_TO_DS_TYPE

View file

@ -13,6 +13,7 @@
#include <mapnik/geometry.hpp> #include <mapnik/geometry.hpp>
#include <mapnik/memory_featureset.hpp> #include <mapnik/memory_featureset.hpp>
#include <mapnik/wkt/wkt_factory.hpp> #include <mapnik/wkt/wkt_factory.hpp>
#include <mapnik/util/geometry_to_ds_type.hpp>
#include <mapnik/ptree_helpers.hpp> // mapnik::boolean #include <mapnik/ptree_helpers.hpp> // mapnik::boolean
// stl // stl
@ -837,7 +838,7 @@ std::string csv_datasource::name()
return "csv"; return "csv";
} }
int csv_datasource::type() const datasource::datasource_t csv_datasource::type() const
{ {
return datasource::Vector; return datasource::Vector;
} }
@ -849,6 +850,29 @@ mapnik::box2d<double> csv_datasource::envelope() const
return extent_; return extent_;
} }
boost::optional<mapnik::datasource::geometry_t> csv_datasource::get_geometry_type() const
{
if (! is_bound_) bind();
boost::optional<mapnik::datasource::geometry_t> result;
int multi_type = 0;
unsigned num_features = features_.size();
for (int i = 0; i < num_features && i < 5; ++i)
{
mapnik::util::to_ds_type(features_[i]->paths(),result);
if (result)
{
int type = static_cast<int>(*result);
if (multi_type > 0 && multi_type != type)
{
result.reset(mapnik::datasource::Collection);
return result;
}
multi_type = type;
}
}
return result;
}
mapnik::layer_descriptor csv_datasource::get_descriptor() const mapnik::layer_descriptor csv_datasource::get_descriptor() const
{ {
if (!is_bound_) bind(); if (!is_bound_) bind();

View file

@ -12,11 +12,12 @@ class csv_datasource : public mapnik::datasource
public: public:
csv_datasource(mapnik::parameters const& params, bool bind=true); csv_datasource(mapnik::parameters const& params, bool bind=true);
virtual ~csv_datasource (); virtual ~csv_datasource ();
int type() const; mapnik::datasource::datasource_t type() const;
static std::string name(); static std::string name();
mapnik::featureset_ptr features(mapnik::query const& q) const; mapnik::featureset_ptr features(mapnik::query const& q) const;
mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const; mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const;
mapnik::box2d<double> envelope() const; mapnik::box2d<double> envelope() const;
boost::optional<mapnik::datasource::geometry_t> get_geometry_type() const;
mapnik::layer_descriptor get_descriptor() const; mapnik::layer_descriptor get_descriptor() const;
void bind() const; void bind() const;
template <typename T> template <typename T>

View file

@ -197,7 +197,7 @@ gdal_datasource::~gdal_datasource()
{ {
} }
int gdal_datasource::type() const datasource::datasource_t gdal_datasource::type() const
{ {
return datasource::Raster; return datasource::Raster;
} }
@ -214,6 +214,11 @@ box2d<double> gdal_datasource::envelope() const
return extent_; return extent_;
} }
boost::optional<mapnik::datasource::geometry_t> gdal_datasource::get_geometry_type() const
{
return boost::optional<mapnik::datasource::geometry_t>();
}
layer_descriptor gdal_datasource::get_descriptor() const layer_descriptor gdal_datasource::get_descriptor() const
{ {
return desc_; return desc_;

View file

@ -37,11 +37,12 @@ class gdal_datasource : public mapnik::datasource
public: public:
gdal_datasource(mapnik::parameters const& params, bool bind = true); gdal_datasource(mapnik::parameters const& params, bool bind = true);
virtual ~gdal_datasource(); virtual ~gdal_datasource();
int type() const; mapnik::datasource::datasource_t type() const;
static std::string name(); static std::string name();
mapnik::featureset_ptr features(mapnik::query const& q) const; mapnik::featureset_ptr features(mapnik::query const& q) const;
mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const; mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const;
mapnik::box2d<double> envelope() const; mapnik::box2d<double> envelope() const;
boost::optional<mapnik::datasource::geometry_t> get_geometry_type() const;
mapnik::layer_descriptor get_descriptor() const; mapnik::layer_descriptor get_descriptor() const;
void bind() const; void bind() const;
private: private:

View file

@ -225,7 +225,7 @@ std::string geos_datasource::name()
return "geos"; return "geos";
} }
int geos_datasource::type() const mapnik::datasource::datasource_t geos_datasource::type() const
{ {
return type_; return type_;
} }
@ -237,6 +237,38 @@ box2d<double> geos_datasource::envelope() const
return extent_; return extent_;
} }
boost::optional<mapnik::datasource::geometry_t> geos_datasource::get_geometry_type() const
{
if (! is_bound_) bind();
boost::optional<mapnik::datasource::geometry_t> result;
// get geometry type
const int type = GEOSGeomTypeId(*geometry_);
switch (type)
{
case GEOS_POINT:
case GEOS_MULTIPOINT:
result.reset(mapnik::datasource::Point);
break;
case GEOS_LINESTRING:
case GEOS_LINEARRING:
case GEOS_MULTILINESTRING:
result.reset(mapnik::datasource::LineString);
break;
case GEOS_POLYGON:
case GEOS_MULTIPOLYGON:
result.reset(mapnik::datasource::Polygon);
break;
case GEOS_GEOMETRYCOLLECTION:
result.reset(mapnik::datasource::Collection);
break;
default:
break;
}
return result;
}
layer_descriptor geos_datasource::get_descriptor() const layer_descriptor geos_datasource::get_descriptor() const
{ {
if (! is_bound_) bind(); if (! is_bound_) bind();

View file

@ -38,18 +38,19 @@ class geos_datasource : public mapnik::datasource
public: public:
geos_datasource(mapnik::parameters const& params, bool bind = true); geos_datasource(mapnik::parameters const& params, bool bind = true);
virtual ~geos_datasource (); virtual ~geos_datasource ();
int type() const; mapnik::datasource::datasource_t type() const;
static std::string name(); static std::string name();
mapnik::featureset_ptr features(mapnik::query const& q) const; mapnik::featureset_ptr features(mapnik::query const& q) const;
mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const; mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const;
mapnik::box2d<double> envelope() const; mapnik::box2d<double> envelope() const;
boost::optional<mapnik::datasource::geometry_t> get_geometry_type() const;
mapnik::layer_descriptor get_descriptor() const; mapnik::layer_descriptor get_descriptor() const;
void bind() const; void bind() const;
private: private:
mutable mapnik::box2d<double> extent_; mutable mapnik::box2d<double> extent_;
mutable bool extent_initialized_; mutable bool extent_initialized_;
int type_; mapnik::datasource::datasource_t type_;
mutable mapnik::layer_descriptor desc_; mutable mapnik::layer_descriptor desc_;
mutable geos_feature_ptr geometry_; mutable geos_feature_ptr geometry_;
mutable std::string geometry_data_; mutable std::string geometry_data_;

View file

@ -131,7 +131,7 @@ std::string kismet_datasource::name()
return "kismet"; return "kismet";
} }
int kismet_datasource::type() const mapnik::datasource::datasource_t kismet_datasource::type() const
{ {
return type_; return type_;
} }
@ -142,6 +142,11 @@ box2d<double> kismet_datasource::envelope() const
return extent_; return extent_;
} }
boost::optional<mapnik::datasource::geometry_t> kismet_datasource::get_geometry_type() const
{
return boost::optional<mapnik::datasource::geometry_t>(mapnik::datasource::Point);
}
layer_descriptor kismet_datasource::get_descriptor() const layer_descriptor kismet_datasource::get_descriptor() const
{ {
return desc_; return desc_;

View file

@ -45,11 +45,12 @@ class kismet_datasource : public mapnik::datasource
public: public:
kismet_datasource(mapnik::parameters const& params, bool bind = true); kismet_datasource(mapnik::parameters const& params, bool bind = true);
virtual ~kismet_datasource (); virtual ~kismet_datasource ();
int type() const; datasource::datasource_t type() const;
static std::string name(); static std::string name();
mapnik::featureset_ptr features(mapnik::query const& q) const; mapnik::featureset_ptr features(mapnik::query const& q) const;
mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const; mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const;
mapnik::box2d<double> envelope() const; mapnik::box2d<double> envelope() const;
boost::optional<mapnik::datasource::geometry_t> get_geometry_type() const;
mapnik::layer_descriptor get_descriptor() const; mapnik::layer_descriptor get_descriptor() const;
void bind() const; void bind() const;
@ -60,9 +61,9 @@ private:
bool extent_initialized_; bool extent_initialized_;
std::string host_; std::string host_;
unsigned int port_; unsigned int port_;
int type_; mapnik::datasource::datasource_t type_;
std::string srs_; std::string srs_;
mapnik::layer_descriptor desc_; mutable mapnik::layer_descriptor desc_;
boost::shared_ptr<boost::thread> kismet_thread; boost::shared_ptr<boost::thread> kismet_thread;
}; };

View file

@ -351,7 +351,7 @@ std::string occi_datasource::name()
return "occi"; return "occi";
} }
int occi_datasource::type() const mapnik::datasource::datasource_t occi_datasource::type() const
{ {
return type_; return type_;
} }
@ -474,6 +474,14 @@ box2d<double> occi_datasource::envelope() const
return extent_; return extent_;
} }
boost::optional<mapnik::datasource::geometry_t> occi_datasource::get_geometry_type() const
{
// FIXME
//if (! is_bound_) bind();
return boost::optional<mapnik::datasource::geometry_t>();
}
layer_descriptor occi_datasource::get_descriptor() const layer_descriptor occi_datasource::get_descriptor() const
{ {
if (! is_bound_) bind(); if (! is_bound_) bind();

View file

@ -40,16 +40,17 @@ class occi_datasource : public mapnik::datasource
public: public:
occi_datasource(mapnik::parameters const& params, bool bind = true); occi_datasource(mapnik::parameters const& params, bool bind = true);
virtual ~occi_datasource (); virtual ~occi_datasource ();
int type() const; mapnik::datasource::datasource_t type() const;
static std::string name(); static std::string name();
mapnik::featureset_ptr features(mapnik::query const& q) const; mapnik::featureset_ptr features(mapnik::query const& q) const;
mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const; mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const;
mapnik::box2d<double> envelope() const; mapnik::box2d<double> envelope() const;
boost::optional<mapnik::datasource::geometry_t> get_geometry_type() const;
mapnik::layer_descriptor get_descriptor() const; mapnik::layer_descriptor get_descriptor() const;
void bind() const; void bind() const;
private: private:
int type_; mapnik::datasource::datasource_t type_;
mutable std::string table_; mutable std::string table_;
mutable std::string table_name_; mutable std::string table_name_;
mutable std::string fields_; mutable std::string fields_;

View file

@ -28,6 +28,7 @@
#include "ogr_datasource.hpp" #include "ogr_datasource.hpp"
#include "ogr_featureset.hpp" #include "ogr_featureset.hpp"
#include "ogr_index_featureset.hpp" #include "ogr_index_featureset.hpp"
#include "ogr_feature_ptr.hpp"
// mapnik // mapnik
#include <mapnik/ptree_helpers.hpp> #include <mapnik/ptree_helpers.hpp>
@ -331,7 +332,7 @@ std::string ogr_datasource::name()
return "ogr"; return "ogr";
} }
int ogr_datasource::type() const mapnik::datasource::datasource_t ogr_datasource::type() const
{ {
return type_; return type_;
} }
@ -342,6 +343,79 @@ box2d<double> ogr_datasource::envelope() const
return extent_; return extent_;
} }
boost::optional<mapnik::datasource::geometry_t> ogr_datasource::get_geometry_type() const
{
boost::optional<mapnik::datasource::geometry_t> result;
if (dataset_ && layer_.is_valid())
{
OGRLayer* layer = layer_.layer();
// NOTE: wkbFlatten macro in ogr flattens 2.5d types into base 2d type
switch (wkbFlatten(layer->GetGeomType()))
{
case wkbPoint:
case wkbMultiPoint:
result.reset(mapnik::datasource::Point);
break;
case wkbLinearRing:
case wkbLineString:
case wkbMultiLineString:
result.reset(mapnik::datasource::LineString);
break;
case wkbPolygon:
case wkbMultiPolygon:
result.reset(mapnik::datasource::Polygon);
break;
case wkbGeometryCollection:
result.reset(mapnik::datasource::Collection);
break;
case wkbNone:
case wkbUnknown:
{
// fallback to inspecting first actual geometry
// TODO - csv and shapefile inspect first 4 features
if (dataset_ && layer_.is_valid())
{
OGRLayer* layer = layer_.layer();
ogr_feature_ptr feat(layer->GetNextFeature());
if ((*feat) != NULL)
{
OGRGeometry* geom = (*feat)->GetGeometryRef();
if (geom && ! geom->IsEmpty())
{
switch (wkbFlatten(geom->getGeometryType()))
{
case wkbPoint:
case wkbMultiPoint:
result.reset(mapnik::datasource::Point);
break;
case wkbLinearRing:
case wkbLineString:
case wkbMultiLineString:
result.reset(mapnik::datasource::LineString);
break;
case wkbPolygon:
case wkbMultiPolygon:
result.reset(mapnik::datasource::Polygon);
break;
case wkbGeometryCollection:
result.reset(mapnik::datasource::Collection);
break;
default:
break;
}
}
}
}
break;
}
default:
break;
}
}
return result;
}
layer_descriptor ogr_datasource::get_descriptor() const layer_descriptor ogr_datasource::get_descriptor() const
{ {
if (! is_bound_) bind(); if (! is_bound_) bind();

View file

@ -41,17 +41,18 @@ class ogr_datasource : public mapnik::datasource
public: public:
ogr_datasource(mapnik::parameters const& params, bool bind=true); ogr_datasource(mapnik::parameters const& params, bool bind=true);
virtual ~ogr_datasource (); virtual ~ogr_datasource ();
int type() const; mapnik::datasource::datasource_t type() const;
static std::string name(); static std::string name();
mapnik::featureset_ptr features(mapnik::query const& q) const; mapnik::featureset_ptr features(mapnik::query const& q) const;
mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const; mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const;
mapnik::box2d<double> envelope() const; mapnik::box2d<double> envelope() const;
boost::optional<mapnik::datasource::geometry_t> get_geometry_type() const;
mapnik::layer_descriptor get_descriptor() const; mapnik::layer_descriptor get_descriptor() const;
void bind() const; void bind() const;
private: private:
mutable mapnik::box2d<double> extent_; mutable mapnik::box2d<double> extent_;
int type_; mapnik::datasource::datasource_t type_;
std::string dataset_name_; std::string dataset_name_;
mutable std::string index_name_; mutable std::string index_name_;
mutable OGRDataSource* dataset_; mutable OGRDataSource* dataset_;

View file

@ -137,7 +137,7 @@ std::string osm_datasource::name()
return "osm"; return "osm";
} }
int osm_datasource::type() const mapnik::datasource::datasource_t osm_datasource::type() const
{ {
return type_; return type_;
} }
@ -189,3 +189,9 @@ box2d<double> osm_datasource::envelope() const
return extent_; return extent_;
} }
boost::optional<mapnik::datasource::geometry_t> osm_datasource::get_geometry_type() const
{
if (! is_bound_) bind();
return boost::optional<mapnik::datasource::geometry_t>(mapnik::datasource::Collection);
}

View file

@ -42,17 +42,18 @@ class osm_datasource : public datasource
public: public:
osm_datasource(const parameters& params, bool bind = true); osm_datasource(const parameters& params, bool bind = true);
virtual ~osm_datasource(); virtual ~osm_datasource();
int type() const; mapnik::datasource::datasource_t type() const;
featureset_ptr features(const query& q) const; featureset_ptr features(const query& q) const;
featureset_ptr features_at_point(coord2d const& pt) const; featureset_ptr features_at_point(coord2d const& pt) const;
box2d<double> envelope() const; box2d<double> envelope() const;
boost::optional<mapnik::datasource::geometry_t> get_geometry_type() const;
layer_descriptor get_descriptor() const; layer_descriptor get_descriptor() const;
static std::string name(); static std::string name();
void bind() const; void bind() const;
private: private:
mutable box2d<double> extent_; mutable box2d<double> extent_;
mutable osm_dataset* osm_data_; mutable osm_dataset* osm_data_;
int type_; mapnik::datasource::datasource_t type_;
mutable layer_descriptor desc_; mutable layer_descriptor desc_;
// no copying // no copying
osm_datasource(const osm_datasource&); osm_datasource(const osm_datasource&);

View file

@ -106,6 +106,8 @@ void postgis_datasource::bind() const
ConnectionManager *mgr=ConnectionManager::instance(); ConnectionManager *mgr=ConnectionManager::instance();
mgr->registerPool(creator_, *initial_size, *max_size); mgr->registerPool(creator_, *initial_size, *max_size);
std::string g_type;
shared_ptr<Pool<Connection,ConnectionCreator> > pool=mgr->getPool(creator_.id()); shared_ptr<Pool<Connection,ConnectionCreator> > pool=mgr->getPool(creator_.id());
if (pool) if (pool)
{ {
@ -113,8 +115,6 @@ void postgis_datasource::bind() const
if (conn && conn->isOK()) if (conn && conn->isOK())
{ {
is_bound_ = true;
PoolGuard<shared_ptr<Connection>, PoolGuard<shared_ptr<Connection>,
shared_ptr<Pool<Connection,ConnectionCreator> > > guard(conn,pool); shared_ptr<Pool<Connection,ConnectionCreator> > > guard(conn,pool);
@ -145,14 +145,20 @@ void postgis_datasource::bind() const
if (!geometryColumn_.length() > 0 || srid_ == 0) if (!geometryColumn_.length() > 0 || srid_ == 0)
{ {
std::ostringstream s; std::ostringstream s;
s << "SELECT f_geometry_column, srid FROM "; s << "SELECT f_geometry_column, srid FROM "
s << GEOMETRY_COLUMNS <<" WHERE f_table_name='" << mapnik::sql_utils::unquote_double(geometry_table_) <<"'"; << GEOMETRY_COLUMNS <<" WHERE f_table_name='"
<< mapnik::sql_utils::unquote_double(geometry_table_)
<< "'";
if (schema_.length() > 0) if (schema_.length() > 0)
s << " AND f_table_schema='" << mapnik::sql_utils::unquote_double(schema_) << "'"; s << " AND f_table_schema='"
<< mapnik::sql_utils::unquote_double(schema_)
<< "'";
if (geometry_field_.length() > 0) if (geometry_field_.length() > 0)
s << " AND f_geometry_column='" << mapnik::sql_utils::unquote_double(geometry_field_) << "'"; s << " AND f_geometry_column='"
<< mapnik::sql_utils::unquote_double(geometry_field_)
<< "'";
/* /*
if (show_queries_) if (show_queries_)
@ -161,7 +167,7 @@ void postgis_datasource::bind() const
} }
*/ */
shared_ptr<ResultSet> rs=conn->executeQuery(s.str()); shared_ptr<ResultSet> rs = conn->executeQuery(s.str());
if (rs->next()) if (rs->next())
{ {
geometryColumn_ = rs->getValue("f_geometry_column"); geometryColumn_ = rs->getValue("f_geometry_column");
@ -196,7 +202,7 @@ void postgis_datasource::bind() const
} }
*/ */
shared_ptr<ResultSet> rs=conn->executeQuery(s.str()); shared_ptr<ResultSet> rs = conn->executeQuery(s.str());
if (rs->next()) if (rs->next())
{ {
try try
@ -238,7 +244,7 @@ void postgis_datasource::bind() const
*/ */
shared_ptr<ResultSet> rs=conn->executeQuery(s.str()); shared_ptr<ResultSet> rs = conn->executeQuery(s.str());
int count = rs->getNumFields(); int count = rs->getNumFields();
bool found_key_field = false; bool found_key_field = false;
for (int i=0;i<count;++i) for (int i=0;i<count;++i)
@ -326,7 +332,11 @@ void postgis_datasource::bind() const
} }
} }
} }
rs->close(); rs->close();
is_bound_ = true;
} }
} }
} }
@ -336,7 +346,7 @@ std::string postgis_datasource::name()
return "postgis"; return "postgis";
} }
int postgis_datasource::type() const mapnik::datasource::datasource_t postgis_datasource::type() const
{ {
return type_; return type_;
} }
@ -686,6 +696,118 @@ box2d<double> postgis_datasource::envelope() const
return extent_; return extent_;
} }
boost::optional<mapnik::datasource::geometry_t> postgis_datasource::get_geometry_type() const
{
if (! is_bound_) bind();
boost::optional<mapnik::datasource::geometry_t> result;
ConnectionManager *mgr=ConnectionManager::instance();
shared_ptr<Pool<Connection,ConnectionCreator> > pool=mgr->getPool(creator_.id());
if (pool)
{
shared_ptr<Connection> conn = pool->borrowObject();
if (conn && conn->isOK())
{
PoolGuard<shared_ptr<Connection>,shared_ptr<Pool<Connection,ConnectionCreator> > > guard(conn,pool);
std::ostringstream s;
std::string g_type;
s << "SELECT lower(type) as type FROM "
<< GEOMETRY_COLUMNS <<" WHERE f_table_name='"
<< mapnik::sql_utils::unquote_double(geometry_table_)
<< "'";
if (schema_.length() > 0)
s << " AND f_table_schema='"
<< mapnik::sql_utils::unquote_double(schema_)
<< "'";
if (geometry_field_.length() > 0)
s << " AND f_geometry_column='"
<< mapnik::sql_utils::unquote_double(geometry_field_)
<< "'";
shared_ptr<ResultSet> rs = conn->executeQuery(s.str());
if (rs->next())
{
g_type = rs->getValue("type");
if (boost::algorithm::contains(g_type,"line"))
{
result.reset(mapnik::datasource::LineString);
return result;
}
else if (boost::algorithm::contains(g_type,"point"))
{
result.reset(mapnik::datasource::Point);
return result;
}
else if (boost::algorithm::contains(g_type,"polygon"))
{
result.reset(mapnik::datasource::Polygon);
return result;
}
else // geometry
{
result.reset(mapnik::datasource::Collection);
return result;
}
}
// fallback to querying first several features
if (g_type.empty() && !geometryColumn_.empty())
{
s.str("");
std::string prev_type("");
s << "SELECT ST_GeometryType(\""
<< geometryColumn_ << "\") AS geom"
<< " FROM " << populate_tokens(table_);
if (row_limit_ > 0 && row_limit_ < 5)
{
s << " LIMIT " << row_limit_;
}
else
{
s << " LIMIT 5";
}
shared_ptr<ResultSet> rs = conn->executeQuery(s.str());
while (rs->next() && !rs->isNull(0))
{
const char* data = rs->getValue(0);
if (boost::algorithm::icontains(data,"line"))
{
g_type = "linestring";
result.reset(mapnik::datasource::LineString);
}
else if (boost::algorithm::icontains(data,"point"))
{
g_type = "point";
result.reset(mapnik::datasource::Point);
}
else if (boost::algorithm::icontains(data,"polygon"))
{
g_type = "polygon";
result.reset(mapnik::datasource::Polygon);
}
else // geometry
{
result.reset(mapnik::datasource::Collection);
return result;
}
if (!prev_type.empty() && g_type != prev_type)
{
result.reset(mapnik::datasource::Collection);
return result;
}
prev_type = g_type;
}
}
}
}
return result;
}
postgis_datasource::~postgis_datasource() postgis_datasource::~postgis_datasource()
{ {
if (is_bound_ && !persist_connection_) if (is_bound_ && !persist_connection_)

View file

@ -63,7 +63,7 @@ class postgis_datasource : public datasource
const int cursor_fetch_size_; const int cursor_fetch_size_;
const int row_limit_; const int row_limit_;
mutable std::string geometryColumn_; mutable std::string geometryColumn_;
int type_; mapnik::datasource::datasource_t type_;
mutable int srid_; mutable int srid_;
mutable bool extent_initialized_; mutable bool extent_initialized_;
mutable mapnik::box2d<double> extent_; mutable mapnik::box2d<double> extent_;
@ -79,10 +79,11 @@ class postgis_datasource : public datasource
//bool show_queries_; //bool show_queries_;
public: public:
static std::string name(); static std::string name();
int type() const; mapnik::datasource::datasource_t type() const;
featureset_ptr features(const query& q) const; featureset_ptr features(const query& q) const;
featureset_ptr features_at_point(coord2d const& pt) const; featureset_ptr features_at_point(coord2d const& pt) const;
mapnik::box2d<double> envelope() const; mapnik::box2d<double> envelope() const;
boost::optional<mapnik::datasource::geometry_t> get_geometry_type() const;
layer_descriptor get_descriptor() const; layer_descriptor get_descriptor() const;
postgis_datasource(const parameters &params, bool bind=true); postgis_datasource(const parameters &params, bool bind=true);
~postgis_datasource(); ~postgis_datasource();

View file

@ -159,7 +159,7 @@ raster_datasource::~raster_datasource()
{ {
} }
int raster_datasource::type() const mapnik::datasource::datasource_t raster_datasource::type() const
{ {
return datasource::Raster; return datasource::Raster;
} }
@ -174,6 +174,11 @@ mapnik::box2d<double> raster_datasource::envelope() const
return extent_; return extent_;
} }
boost::optional<mapnik::datasource::geometry_t> raster_datasource::get_geometry_type() const
{
return boost::optional<mapnik::datasource::geometry_t>();
}
layer_descriptor raster_datasource::get_descriptor() const layer_descriptor raster_datasource::get_descriptor() const
{ {
return desc_; return desc_;

View file

@ -33,11 +33,12 @@ class raster_datasource : public mapnik::datasource
public: public:
raster_datasource(const mapnik::parameters& params, bool bind=true); raster_datasource(const mapnik::parameters& params, bool bind=true);
virtual ~raster_datasource(); virtual ~raster_datasource();
int type() const; datasource::datasource_t type() const;
static std::string name(); static std::string name();
mapnik::featureset_ptr features(const mapnik::query& q) const; mapnik::featureset_ptr features(const mapnik::query& q) const;
mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const; mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const;
mapnik::box2d<double> envelope() const; mapnik::box2d<double> envelope() const;
boost::optional<mapnik::datasource::geometry_t> get_geometry_type() const;
mapnik::layer_descriptor get_descriptor() const; mapnik::layer_descriptor get_descriptor() const;
void bind() const; void bind() const;
private: private:

View file

@ -36,7 +36,7 @@ class rasterlite_datasource : public mapnik::datasource
public: public:
rasterlite_datasource(mapnik::parameters const& params, bool bind = true); rasterlite_datasource(mapnik::parameters const& params, bool bind = true);
virtual ~rasterlite_datasource (); virtual ~rasterlite_datasource ();
int type() const; mapnik::datasource::datasource_t type() const;
static std::string name(); static std::string name();
mapnik::featureset_ptr features(mapnik::query const& q) const; mapnik::featureset_ptr features(mapnik::query const& q) const;
mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const; mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const;

View file

@ -182,8 +182,8 @@ void shape_datasource::init(shape_io& shape) const
throw datasource_exception("Shape Plugin: " + (boost::format("invalid version number: %d") % version).str()); throw datasource_exception("Shape Plugin: " + (boost::format("invalid version number: %d") % version).str());
} }
int shape_type = shape.shp().read_ndr_integer(); shape_type_ = static_cast<shape_io::shapeType>(shape.shp().read_ndr_integer());
if (shape_type == shape_io::shape_multipatch) if (shape_type_ == shape_io::shape_multipatch)
throw datasource_exception("Shape Plugin: shapefile multipatch type is not supported"); throw datasource_exception("Shape Plugin: shapefile multipatch type is not supported");
shape.shp().read_envelope(extent_); shape.shp().read_envelope(extent_);
@ -229,7 +229,7 @@ std::string shape_datasource::name()
return "shape"; return "shape";
} }
int shape_datasource::type() const datasource::datasource_t shape_datasource::type() const
{ {
return type_; return type_;
} }
@ -314,3 +314,39 @@ box2d<double> shape_datasource::envelope() const
return extent_; return extent_;
} }
boost::optional<mapnik::datasource::geometry_t> shape_datasource::get_geometry_type() const
{
boost::optional<mapnik::datasource::geometry_t> result;
switch (shape_type_)
{
case shape_io::shape_point:
case shape_io::shape_pointm:
case shape_io::shape_pointz:
case shape_io::shape_multipoint:
case shape_io::shape_multipointm:
case shape_io::shape_multipointz:
{
result.reset(mapnik::datasource::Point);
break;
}
case shape_io::shape_polyline:
case shape_io::shape_polylinem:
case shape_io::shape_polylinez:
{
result.reset(mapnik::datasource::LineString);
break;
}
case shape_io::shape_polygon:
case shape_io::shape_polygonm:
case shape_io::shape_polygonz:
{
result.reset(mapnik::datasource::Polygon);
break;
}
default:
break;
}
return result;
}

View file

@ -45,11 +45,12 @@ public:
shape_datasource(const parameters &params, bool bind=true); shape_datasource(const parameters &params, bool bind=true);
virtual ~shape_datasource(); virtual ~shape_datasource();
int type() const; datasource::datasource_t type() const;
static std::string name(); static std::string name();
featureset_ptr features(const query& q) const; featureset_ptr features(const query& q) const;
featureset_ptr features_at_point(coord2d const& pt) const; featureset_ptr features_at_point(coord2d const& pt) const;
box2d<double> envelope() const; box2d<double> envelope() const;
boost::optional<mapnik::datasource::geometry_t> get_geometry_type() const;
layer_descriptor get_descriptor() const; layer_descriptor get_descriptor() const;
void bind() const; void bind() const;
private: private:
@ -57,9 +58,10 @@ private:
shape_datasource& operator=(const shape_datasource&); shape_datasource& operator=(const shape_datasource&);
void init(shape_io& shape) const; void init(shape_io& shape) const;
private: private:
int type_; datasource::datasource_t type_;
std::string shape_name_; std::string shape_name_;
mutable boost::shared_ptr<shape_io> shape_; mutable boost::shared_ptr<shape_io> shape_;
mutable shape_io::shapeType shape_type_;
mutable long file_length_; mutable long file_length_;
mutable box2d<double> extent_; mutable box2d<double> extent_;
mutable bool indexed_; mutable bool indexed_;

View file

@ -71,7 +71,7 @@ void shape_io::move_to(int pos)
shp_.seek(pos); shp_.seek(pos);
id_ = shp_.read_xdr_integer(); id_ = shp_.read_xdr_integer();
reclength_ = shp_.read_xdr_integer(); reclength_ = shp_.read_xdr_integer();
type_ = shp_.read_ndr_integer(); type_ = static_cast<shape_io::shapeType>(shp_.read_ndr_integer());
if (type_ != shape_null && type_ != shape_point && type_ != shape_pointm && type_ != shape_pointz) if (type_ != shape_null && type_ != shape_point && type_ != shape_pointm && type_ != shape_pointz)
{ {
@ -79,7 +79,7 @@ void shape_io::move_to(int pos)
} }
} }
int shape_io::type() const shape_io::shapeType shape_io::type() const
{ {
return type_; return type_;
} }

View file

@ -25,6 +25,8 @@
// mapnik // mapnik
#include <mapnik/geometry.hpp> #include <mapnik/geometry.hpp>
#include <mapnik/datasource.hpp>
// boost // boost
#include <boost/utility.hpp> #include <boost/utility.hpp>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
@ -71,11 +73,11 @@ public:
} }
void move_to(int id); void move_to(int id);
int type() const; shapeType type() const;
const box2d<double>& current_extent() const; const box2d<double>& current_extent() const;
void read_polyline(mapnik::geometry_container & geom); void read_polyline(mapnik::geometry_container & geom);
void read_polygon(mapnik::geometry_container & geom); void read_polygon(mapnik::geometry_container & geom);
unsigned type_; shapeType type_;
shape_file shp_; shape_file shp_;
dbf_file dbf_; dbf_file dbf_;
boost::shared_ptr<shape_file> index_; boost::shared_ptr<shape_file> index_;

View file

@ -28,6 +28,8 @@
// mapnik // mapnik
#include <mapnik/ptree_helpers.hpp> #include <mapnik/ptree_helpers.hpp>
#include <mapnik/sql_utils.hpp> #include <mapnik/sql_utils.hpp>
#include <mapnik/util/geometry_to_ds_type.hpp>
#include <mapnik/wkb.hpp>
// boost // boost
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
@ -69,16 +71,12 @@ sqlite_datasource::sqlite_datasource(parameters const& params, bool bind)
/* TODO /* TODO
- throw if no primary key but spatial index is present? - throw if no primary key but spatial index is present?
- remove auto-indexing - remove auto-indexing
- if spatialite - leverage more of the metadata for geometry type detection
*/ */
boost::optional<std::string> file = params_.get<std::string>("file"); boost::optional<std::string> file = params_.get<std::string>("file");
if (! file) throw datasource_exception("Sqlite Plugin: missing <file> parameter"); if (! file) throw datasource_exception("Sqlite Plugin: missing <file> parameter");
if (table_.empty())
{
throw mapnik::datasource_exception("Sqlite Plugin: missing <table> parameter");
}
if (bind) if (bind)
{ {
this->bind(); this->bind();
@ -147,6 +145,44 @@ void sqlite_datasource::bind() const
init_statements_.push_back(*initdb); init_statements_.push_back(*initdb);
} }
// now actually create the connection and start executing setup sql
dataset_ = boost::make_shared<sqlite_connection>(dataset_name_);
boost::optional<unsigned> table_by_index = params_.get<unsigned>("table_by_index");
int passed_parameters = 0;
passed_parameters += params_.get<std::string>("table") ? 1 : 0;
passed_parameters += table_by_index ? 1 : 0;
if (passed_parameters > 1)
{
throw datasource_exception("SQLite Plugin: you can only select an by name "
"('table' parameter), by number ('table_by_index' parameter), "
"do not supply 2 or more of them at the same time" );
}
if (table_by_index)
{
std::vector<std::string> tables;
sqlite_utils::get_tables(dataset_,tables);
if (*table_by_index >= tables.size())
{
std::ostringstream s;
s << "SQLite Plugin: only "
<< tables.size()
<< " table(s) exist, cannot find table by index '" << *table_by_index << "'";
throw datasource_exception(s.str());
}
table_ = tables[*table_by_index];
}
if (table_.empty())
{
throw mapnik::datasource_exception("Sqlite Plugin: missing <table> parameter");
}
if (geometry_table_.empty()) if (geometry_table_.empty())
{ {
geometry_table_ = mapnik::sql_utils::table_from_sql(table_); geometry_table_ = mapnik::sql_utils::table_from_sql(table_);
@ -169,9 +205,6 @@ void sqlite_datasource::bind() const
} }
} }
// now actually create the connection and start executing setup sql
dataset_ = boost::make_shared<sqlite_connection>(dataset_name_);
// Execute init_statements_ // Execute init_statements_
for (std::vector<std::string>::const_iterator iter = init_statements_.begin(); for (std::vector<std::string>::const_iterator iter = init_statements_.begin();
iter != init_statements_.end(); ++iter) iter != init_statements_.end(); ++iter)
@ -188,7 +221,11 @@ void sqlite_datasource::bind() const
std::ostringstream s; std::ostringstream s;
std::string query = populate_tokens(table_); std::string query = populate_tokens(table_);
s << "SELECT " << fields_ << " FROM (" << query << ") LIMIT 1"; s << "SELECT " << fields_ << " FROM (" << query << ") LIMIT 1";
found_types_via_subquery = sqlite_utils::detect_types_from_subquery(s.str(),geometry_field_,desc_,dataset_); found_types_via_subquery = sqlite_utils::detect_types_from_subquery(
s.str(),
geometry_field_,
desc_,
dataset_);
} }
// TODO - consider removing this // TODO - consider removing this
@ -328,6 +365,7 @@ void sqlite_datasource::bind() const
throw datasource_exception(s.str()); throw datasource_exception(s.str());
} }
} }
is_bound_ = true; is_bound_ = true;
} }
@ -434,7 +472,7 @@ std::string sqlite_datasource::name()
return "sqlite"; return "sqlite";
} }
int sqlite_datasource::type() const mapnik::datasource::datasource_t sqlite_datasource::type() const
{ {
return type_; return type_;
} }
@ -446,6 +484,53 @@ box2d<double> sqlite_datasource::envelope() const
return extent_; return extent_;
} }
boost::optional<mapnik::datasource::geometry_t> sqlite_datasource::get_geometry_type() const
{
if (! is_bound_) bind();
boost::optional<mapnik::datasource::geometry_t> result;
if (dataset_)
{
// finally, get geometry type by querying first feature
std::ostringstream s;
s << "SELECT " << geometry_field_
<< " FROM " << geometry_table_;
if (row_limit_ > 0 && row_limit_ < 5)
{
s << " LIMIT " << row_limit_;
}
else
{
s << " LIMIT 5";
}
boost::shared_ptr<sqlite_resultset> rs = dataset_->execute_query(s.str());
int multi_type = 0;
while (rs->is_valid() && rs->step_next())
{
int size;
const char* data = (const char*) rs->column_blob(0, size);
if (data)
{
boost::ptr_vector<mapnik::geometry_type> paths;
mapnik::geometry_utils::from_wkb(paths, data, size, mapnik::wkbAuto);
mapnik::util::to_ds_type(paths,result);
if (result)
{
int type = static_cast<int>(*result);
if (multi_type > 0 && multi_type != type)
{
result.reset(mapnik::datasource::Collection);
return result;
}
multi_type = type;
}
}
}
}
return result;
}
layer_descriptor sqlite_datasource::get_descriptor() const layer_descriptor sqlite_datasource::get_descriptor() const
{ {
if (! is_bound_) bind(); if (! is_bound_) bind();

View file

@ -42,11 +42,12 @@ class sqlite_datasource : public mapnik::datasource
public: public:
sqlite_datasource(mapnik::parameters const& params, bool bind = true); sqlite_datasource(mapnik::parameters const& params, bool bind = true);
virtual ~sqlite_datasource (); virtual ~sqlite_datasource ();
int type() const; datasource::datasource_t type() const;
static std::string name(); static std::string name();
mapnik::featureset_ptr features(mapnik::query const& q) const; mapnik::featureset_ptr features(mapnik::query const& q) const;
mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const; mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const;
mapnik::box2d<double> envelope() const; mapnik::box2d<double> envelope() const;
boost::optional<mapnik::datasource::geometry_t> get_geometry_type() const;
mapnik::layer_descriptor get_descriptor() const; mapnik::layer_descriptor get_descriptor() const;
void bind() const; void bind() const;
@ -58,7 +59,7 @@ private:
mutable mapnik::box2d<double> extent_; mutable mapnik::box2d<double> extent_;
mutable bool extent_initialized_; mutable bool extent_initialized_;
int type_; mapnik::datasource::datasource_t type_;
mutable std::string dataset_name_; mutable std::string dataset_name_;
mutable boost::shared_ptr<sqlite_connection> dataset_; mutable boost::shared_ptr<sqlite_connection> dataset_;
mutable std::string table_; mutable std::string table_;

View file

@ -12,8 +12,7 @@ using mapnik::parameters;
DATASOURCE_PLUGIN(hello_datasource) DATASOURCE_PLUGIN(hello_datasource)
hello_datasource::hello_datasource(parameters const& params, bool bind) hello_datasource::hello_datasource(parameters const& params, bool bind)
: datasource(params), : datasource(params)
type_(datasource::Vector),
desc_(*params_.get<std::string>("type"), *params_.get<std::string>("encoding","utf-8")), desc_(*params_.get<std::string>("type"), *params_.get<std::string>("encoding","utf-8")),
extent_() extent_()
{ {
@ -34,6 +33,10 @@ void hello_datasource::bind() const
// see http://spatialreference.org/ref/epsg/4326/ for more details // see http://spatialreference.org/ref/epsg/4326/ for more details
extent_.init(-180,-90,180,90); 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; is_bound_ = true;
} }
@ -47,9 +50,9 @@ std::string hello_datasource::name()
return name_; return name_;
} }
int hello_datasource::type() const mapnik::datasource::datasource_t hello_datasource::type() const
{ {
return type_; return datasource::Vector;
} }
mapnik::box2d<double> hello_datasource::envelope() const mapnik::box2d<double> hello_datasource::envelope() const
@ -59,6 +62,11 @@ mapnik::box2d<double> hello_datasource::envelope() const
return extent_; return extent_;
} }
boost::optional<mapnik::datasource::geometry_t> hello_datasource::get_geometry_type() const
{
boost::optional<mapnik::datasource::geometry_t>(mapnik::datasource::Point);
}
mapnik::layer_descriptor hello_datasource::get_descriptor() const mapnik::layer_descriptor hello_datasource::get_descriptor() const
{ {
if (!is_bound_) bind(); if (!is_bound_) bind();

View file

@ -15,7 +15,7 @@ public:
virtual ~hello_datasource (); virtual ~hello_datasource ();
// mandatory: type of the plugin, used to match at runtime // mandatory: type of the plugin, used to match at runtime
int type() const; mapnik::datasource::datasource_t type() const;
// mandatory: name of the plugin // mandatory: name of the plugin
static std::string name(); static std::string name();
@ -31,6 +31,9 @@ public:
// mandatory: return the box2d of the datasource // mandatory: return the box2d of the datasource
// called during rendering to determine if the layer should be processed // called during rendering to determine if the layer should be processed
mapnik::box2d<double> envelope() const; mapnik::box2d<double> envelope() const;
// mandatory: optionally return the overal geometry type of the datasource
boost::optional<mapnik::datasource::geometry_t> get_geometry_type() const;
// mandatory: return the layer descriptor // mandatory: return the layer descriptor
mapnik::layer_descriptor get_descriptor() const; mapnik::layer_descriptor get_descriptor() const;
@ -42,7 +45,6 @@ private:
// recommended naming convention of datasource members: // recommended naming convention of datasource members:
// name_, type_, extent_, and desc_ // name_, type_, extent_, and desc_
static const std::string name_; static const std::string name_;
int type_;
mutable mapnik::layer_descriptor desc_; mutable mapnik::layer_descriptor desc_;
mutable mapnik::box2d<double> extent_; mutable mapnik::box2d<double> extent_;
}; };

View file

@ -143,6 +143,7 @@ void datasource_cache::register_datasources(const std::string& str)
mapnik::CreateStatic>::mutex_); mapnik::CreateStatic>::mutex_);
#endif #endif
boost::filesystem::path path(str); boost::filesystem::path path(str);
// TODO - only push unique paths
plugin_directories_.push_back(str); plugin_directories_.push_back(str);
boost::filesystem::directory_iterator end_itr; boost::filesystem::directory_iterator end_itr;

View file

@ -69,7 +69,7 @@ void memory_datasource::push(feature_ptr feature)
features_.push_back(feature); features_.push_back(feature);
} }
int memory_datasource::type() const datasource::datasource_t memory_datasource::type() const
{ {
return datasource::Vector; return datasource::Vector;
} }
@ -96,6 +96,12 @@ box2d<double> memory_datasource::envelope() const
std::for_each(features_.begin(),features_.end(),func); std::for_each(features_.begin(),features_.end(),func);
return ext; return ext;
} }
boost::optional<datasource::geometry_t> memory_datasource::get_geometry_type() const
{
// TODO - detect this?
return datasource::Collection;
}
layer_descriptor memory_datasource::get_descriptor() const layer_descriptor memory_datasource::get_descriptor() const
{ {
@ -118,7 +124,7 @@ void point_datasource::add_point(double x, double y, const char* key, const char
{ {
feature_ptr feature(feature_factory::create(feature_id_)); feature_ptr feature(feature_factory::create(feature_id_));
++feature_id_; ++feature_id_;
geometry_type * pt = new geometry_type(Point); geometry_type * pt = new geometry_type(mapnik::Point);
pt->move_to(x,y); pt->move_to(x,y);
feature->add_geometry(pt); feature->add_geometry(pt);
transcoder tr("utf-8"); transcoder tr("utf-8");

4178
tests/data/csv/10m-land.csv Normal file

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,3 @@
type,WKT
linestring, "LINESTRING (30 10, 10 30, 40 40)"
multilinestring, "MULTILINESTRING ((10 10, 20 20, 10 40),(40 40, 30 30, 40 20, 30 10))"
1 type WKT
2 linestring LINESTRING (30 10, 10 30, 40 40)
3 multilinestring MULTILINESTRING ((10 10, 20 20, 10 40),(40 40, 30 30, 40 20, 30 10))

View file

@ -0,0 +1,5 @@
type,WKT
polygon, "POLYGON ((30 10, 10 20, 20 40, 40 40, 30 10))"
polygon, "POLYGON ((35 10, 10 20, 15 40, 45 45, 35 10),(20 30, 35 35, 30 20, 20 30))"
multipolygon, "MULTIPOLYGON (((30 20, 10 40, 45 40, 30 20)),((15 5, 40 10, 10 20, 5 10, 15 5)))"
multipolygon, "MULTIPOLYGON (((40 40, 20 45, 45 30, 40 40)),((20 35, 45 20, 30 5, 10 10, 10 30, 20 35),(30 20, 20 25, 20 15, 30 20)))"
1 type WKT
2 polygon POLYGON ((30 10, 10 20, 20 40, 40 40, 30 10))
3 polygon POLYGON ((35 10, 10 20, 15 40, 45 45, 35 10),(20 30, 35 35, 30 20, 20 30))
4 multipolygon MULTIPOLYGON (((30 20, 10 40, 45 40, 30 20)),((15 5, 40 10, 10 20, 5 10, 15 5)))
5 multipolygon MULTIPOLYGON (((40 40, 20 45, 45 30, 40 40)),((20 35, 45 20, 30 5, 10 10, 10 30, 20 35),(30 20, 20 25, 20 15, 30 20)))

View file

@ -0,0 +1,3 @@
type,WKT
point, "POINT (30 10)"
multipoint, "MULTIPOINT ((10 40), (40 30), (20 20), (30 10))"
1 type WKT
2 point POINT (30 10)
3 multipoint MULTIPOINT ((10 40), (40 30), (20 20), (30 10))

View file

@ -0,0 +1,3 @@
type,WKT
polygon, "POLYGON ((30 10, 10 20, 20 40, 40 40, 30 10))"
polygon, "POLYGON ((35 10, 10 20, 15 40, 45 45, 35 10),(20 30, 35 35, 30 20, 20 30))"
1 type WKT
2 polygon POLYGON ((30 10, 10 20, 20 40, 40 40, 30 10))
3 polygon POLYGON ((35 10, 10 20, 15 40, 45 45, 35 10),(20 30, 35 35, 30 20, 20 30))

View file

@ -54,12 +54,14 @@ if 'csv' in mapnik.DatasourceCache.instance().plugin_names():
attr = {'City': u'New York, NY', 'geo_accuracy': u'house', 'Phone': u'(212) 334-0711', 'Address': u'19 Elizabeth Street', 'Precinct': u'5th Precinct', 'geo_longitude': -70, 'geo_latitude': 40} attr = {'City': u'New York, NY', 'geo_accuracy': u'house', 'Phone': u'(212) 334-0711', 'Address': u'19 Elizabeth Street', 'Precinct': u'5th Precinct', 'geo_longitude': -70, 'geo_latitude': 40}
eq_(feat.attributes,attr) eq_(feat.attributes,attr)
eq_(len(ds.all_features()),2) eq_(len(ds.all_features()),2)
eq_(ds.describe(),{'geometry_type': mapnik.DataGeometryType.Point, 'type': mapnik.DataType.Vector, 'name': 'csv', 'encoding': 'utf-8'})
def test_skipping_blank_rows(**kwargs): def test_skipping_blank_rows(**kwargs):
ds = get_csv_ds('blank_rows.csv') ds = get_csv_ds('blank_rows.csv')
eq_(ds.fields(),['x','y','name']) eq_(ds.fields(),['x','y','name'])
eq_(ds.field_types(),['int','int','str']) eq_(ds.field_types(),['int','int','str'])
eq_(len(ds.all_features()),2) eq_(len(ds.all_features()),2)
eq_(ds.describe(),{'geometry_type': mapnik.DataGeometryType.Point, 'type': mapnik.DataType.Vector, 'name': 'csv', 'encoding': 'utf-8'})
def test_empty_rows(**kwargs): def test_empty_rows(**kwargs):
ds = get_csv_ds('empty_rows.csv') ds = get_csv_ds('empty_rows.csv')
@ -75,6 +77,7 @@ if 'csv' in mapnik.DatasourceCache.instance().plugin_names():
eq_(len(feat),10) eq_(len(feat),10)
eq_(feat['empty_column'],u'') eq_(feat['empty_column'],u'')
feat = fs.next() feat = fs.next()
eq_(ds.describe(),{'geometry_type': mapnik.DataGeometryType.Point, 'type': mapnik.DataType.Vector, 'name': 'csv', 'encoding': 'utf-8'})
def test_slashes(**kwargs): def test_slashes(**kwargs):
ds = get_csv_ds('has_attributes_with_slashes.csv') ds = get_csv_ds('has_attributes_with_slashes.csv')
@ -83,6 +86,7 @@ if 'csv' in mapnik.DatasourceCache.instance().plugin_names():
eq_(fs[0].attributes,{'x':0,'y':0,'name':u'a/a'}) eq_(fs[0].attributes,{'x':0,'y':0,'name':u'a/a'})
eq_(fs[1].attributes,{'x':1,'y':4,'name':u'b/b'}) eq_(fs[1].attributes,{'x':1,'y':4,'name':u'b/b'})
eq_(fs[2].attributes,{'x':10,'y':2.5,'name':u'c/c'}) eq_(fs[2].attributes,{'x':10,'y':2.5,'name':u'c/c'})
eq_(ds.describe(),{'geometry_type': mapnik.DataGeometryType.Point, 'type': mapnik.DataType.Vector, 'name': 'csv', 'encoding': 'utf-8'})
def test_wkt_field(**kwargs): def test_wkt_field(**kwargs):
ds = get_csv_ds('wkt.csv') ds = get_csv_ds('wkt.csv')
@ -92,24 +96,25 @@ if 'csv' in mapnik.DatasourceCache.instance().plugin_names():
fs = ds.all_features() fs = ds.all_features()
#import pdb;pdb.set_trace() #import pdb;pdb.set_trace()
eq_(len(fs[0].geometries()),1) eq_(len(fs[0].geometries()),1)
eq_(fs[0].geometries()[0].type(),mapnik.GeometryType.Point) eq_(fs[0].geometries()[0].type(),mapnik.DataGeometryType.Point)
eq_(len(fs[1].geometries()),1) eq_(len(fs[1].geometries()),1)
eq_(fs[1].geometries()[0].type(),mapnik.GeometryType.LineString) eq_(fs[1].geometries()[0].type(),mapnik.DataGeometryType.LineString)
eq_(len(fs[2].geometries()),1) eq_(len(fs[2].geometries()),1)
eq_(fs[2].geometries()[0].type(),mapnik.GeometryType.Polygon) eq_(fs[2].geometries()[0].type(),mapnik.DataGeometryType.Polygon)
eq_(len(fs[3].geometries()),1) # one geometry, two parts eq_(len(fs[3].geometries()),1) # one geometry, two parts
eq_(fs[3].geometries()[0].type(),mapnik.GeometryType.Polygon) eq_(fs[3].geometries()[0].type(),mapnik.DataGeometryType.Polygon)
# tests assuming we want to flatten geometries # tests assuming we want to flatten geometries
# ideally we should not have to: # ideally we should not have to:
# https://github.com/mapnik/mapnik/issues?labels=multigeom+robustness&sort=created&direction=desc&state=open&page=1 # https://github.com/mapnik/mapnik/issues?labels=multigeom+robustness&sort=created&direction=desc&state=open&page=1
eq_(len(fs[4].geometries()),4) eq_(len(fs[4].geometries()),4)
eq_(fs[4].geometries()[0].type(),mapnik.GeometryType.Point) eq_(fs[4].geometries()[0].type(),mapnik.DataGeometryType.Point)
eq_(len(fs[5].geometries()),2) eq_(len(fs[5].geometries()),2)
eq_(fs[5].geometries()[0].type(),mapnik.GeometryType.LineString) eq_(fs[5].geometries()[0].type(),mapnik.DataGeometryType.LineString)
eq_(len(fs[6].geometries()),2) eq_(len(fs[6].geometries()),2)
eq_(fs[6].geometries()[0].type(),mapnik.GeometryType.Polygon) eq_(fs[6].geometries()[0].type(),mapnik.DataGeometryType.Polygon)
eq_(len(fs[7].geometries()),2) eq_(len(fs[7].geometries()),2)
eq_(fs[7].geometries()[0].type(),mapnik.GeometryType.Polygon) eq_(fs[7].geometries()[0].type(),mapnik.DataGeometryType.Polygon)
eq_(ds.describe(),{'geometry_type': mapnik.DataGeometryType.Collection, 'type': mapnik.DataType.Vector, 'name': 'csv', 'encoding': 'utf-8'})
def test_handling_of_missing_header(**kwargs): def test_handling_of_missing_header(**kwargs):
@ -119,6 +124,7 @@ if 'csv' in mapnik.DatasourceCache.instance().plugin_names():
fs = ds.featureset() fs = ds.featureset()
feat = fs.next() feat = fs.next()
eq_(feat['_4'],'missing') eq_(feat['_4'],'missing')
eq_(ds.describe(),{'geometry_type': mapnik.DataGeometryType.Point, 'type': mapnik.DataType.Vector, 'name': 'csv', 'encoding': 'utf-8'})
def test_handling_of_headers_that_are_numbers(**kwargs): def test_handling_of_headers_that_are_numbers(**kwargs):
ds = get_csv_ds('numbers_for_headers.csv') ds = get_csv_ds('numbers_for_headers.csv')
@ -144,6 +150,7 @@ if 'csv' in mapnik.DatasourceCache.instance().plugin_names():
eq_(fs[2]['label'],"0,5") eq_(fs[2]['label'],"0,5")
eq_(fs[3]['label'],"5,0") eq_(fs[3]['label'],"5,0")
eq_(fs[4]['label'],"2.5,2.5") eq_(fs[4]['label'],"2.5,2.5")
eq_(ds.describe(),{'geometry_type': mapnik.DataGeometryType.Point, 'type': mapnik.DataType.Vector, 'name': 'csv', 'encoding': 'utf-8'})
def test_windows_newlines(**kwargs): def test_windows_newlines(**kwargs):
ds = get_csv_ds('windows_newlines.csv') ds = get_csv_ds('windows_newlines.csv')
@ -155,6 +162,7 @@ if 'csv' in mapnik.DatasourceCache.instance().plugin_names():
eq_(feat['x'],1) eq_(feat['x'],1)
eq_(feat['y'],10) eq_(feat['y'],10)
eq_(feat['z'],9999.9999) eq_(feat['z'],9999.9999)
eq_(ds.describe(),{'geometry_type': mapnik.DataGeometryType.Point, 'type': mapnik.DataType.Vector, 'name': 'csv', 'encoding': 'utf-8'})
def test_mac_newlines(**kwargs): def test_mac_newlines(**kwargs):
ds = get_csv_ds('windows_newlines.csv') ds = get_csv_ds('windows_newlines.csv')
@ -166,6 +174,7 @@ if 'csv' in mapnik.DatasourceCache.instance().plugin_names():
eq_(feat['x'],1) eq_(feat['x'],1)
eq_(feat['y'],10) eq_(feat['y'],10)
eq_(feat['z'],9999.9999) eq_(feat['z'],9999.9999)
eq_(ds.describe(),{'geometry_type': mapnik.DataGeometryType.Point, 'type': mapnik.DataType.Vector, 'name': 'csv', 'encoding': 'utf-8'})
def test_tabs(**kwargs): def test_tabs(**kwargs):
ds = get_csv_ds('tabs_in_csv.csv') ds = get_csv_ds('tabs_in_csv.csv')
@ -176,6 +185,7 @@ if 'csv' in mapnik.DatasourceCache.instance().plugin_names():
eq_(feat['x'],-122) eq_(feat['x'],-122)
eq_(feat['y'],48) eq_(feat['y'],48)
eq_(feat['z'],0) eq_(feat['z'],0)
eq_(ds.describe(),{'geometry_type': mapnik.DataGeometryType.Point, 'type': mapnik.DataType.Vector, 'name': 'csv', 'encoding': 'utf-8'})
def test_separator_pipes(**kwargs): def test_separator_pipes(**kwargs):
ds = get_csv_ds('pipe_delimiters.csv') ds = get_csv_ds('pipe_delimiters.csv')
@ -186,6 +196,7 @@ if 'csv' in mapnik.DatasourceCache.instance().plugin_names():
eq_(feat['x'],0) eq_(feat['x'],0)
eq_(feat['y'],0) eq_(feat['y'],0)
eq_(feat['z'],'hello') eq_(feat['z'],'hello')
eq_(ds.describe(),{'geometry_type': mapnik.DataGeometryType.Point, 'type': mapnik.DataType.Vector, 'name': 'csv', 'encoding': 'utf-8'})
def test_separator_semicolon(**kwargs): def test_separator_semicolon(**kwargs):
ds = get_csv_ds('semicolon_delimiters.csv') ds = get_csv_ds('semicolon_delimiters.csv')
@ -196,6 +207,7 @@ if 'csv' in mapnik.DatasourceCache.instance().plugin_names():
eq_(feat['x'],0) eq_(feat['x'],0)
eq_(feat['y'],0) eq_(feat['y'],0)
eq_(feat['z'],'hello') eq_(feat['z'],'hello')
eq_(ds.describe(),{'geometry_type': mapnik.DataGeometryType.Point, 'type': mapnik.DataType.Vector, 'name': 'csv', 'encoding': 'utf-8'})
def test_that_null_and_bool_keywords_are_empty_strings(**kwargs): def test_that_null_and_bool_keywords_are_empty_strings(**kwargs):
ds = get_csv_ds('nulls_and_booleans_as_strings.csv') ds = get_csv_ds('nulls_and_booleans_as_strings.csv')
@ -213,6 +225,7 @@ if 'csv' in mapnik.DatasourceCache.instance().plugin_names():
eq_(feat['y'],0) eq_(feat['y'],0)
eq_(feat['null'],'') eq_(feat['null'],'')
eq_(feat['boolean'],'false') eq_(feat['boolean'],'false')
eq_(ds.describe(),{'geometry_type': mapnik.DataGeometryType.Point, 'type': mapnik.DataType.Vector, 'name': 'csv', 'encoding': 'utf-8'})
@raises(RuntimeError) @raises(RuntimeError)
def test_that_nonexistant_query_field_throws(**kwargs): def test_that_nonexistant_query_field_throws(**kwargs):
@ -226,6 +239,7 @@ if 'csv' in mapnik.DatasourceCache.instance().plugin_names():
# also add an invalid one, triggering throw # also add an invalid one, triggering throw
query.add_property_name('bogus') query.add_property_name('bogus')
fs = ds.features(query) fs = ds.features(query)
eq_(ds.describe(),{'geometry_type': mapnik.DataGeometryType.Point, 'type': mapnik.DataType.Vector, 'name': 'csv', 'encoding': 'utf-8'})
def test_that_leading_zeros_mean_strings(**kwargs): def test_that_leading_zeros_mean_strings(**kwargs):
ds = get_csv_ds('leading_zeros.csv') ds = get_csv_ds('leading_zeros.csv')
@ -245,6 +259,17 @@ if 'csv' in mapnik.DatasourceCache.instance().plugin_names():
eq_(feat['x'],0) eq_(feat['x'],0)
eq_(feat['y'],0) eq_(feat['y'],0)
eq_(feat['fips'],'005') eq_(feat['fips'],'005')
eq_(ds.describe(),{'geometry_type': mapnik.DataGeometryType.Point, 'type': mapnik.DataType.Vector, 'name': 'csv', 'encoding': 'utf-8'})
def test_advanced_geometry_detection(**kwargs):
ds = get_csv_ds('point_wkt.csv')
eq_(ds.describe()['geometry_type'],mapnik.DataGeometryType.Point)
ds = get_csv_ds('poly_wkt.csv')
eq_(ds.describe()['geometry_type'],mapnik.DataGeometryType.Polygon)
ds = get_csv_ds('multi_poly_wkt.csv')
eq_(ds.describe()['geometry_type'],mapnik.DataGeometryType.Polygon)
ds = get_csv_ds('line_wkt.csv')
eq_(ds.describe()['geometry_type'],mapnik.DataGeometryType.LineString)
if __name__ == "__main__": if __name__ == "__main__":
setup() setup()

View file

@ -15,65 +15,68 @@ def test_that_datasources_exist():
print '***NOTICE*** - no datasource plugins have been loaded' print '***NOTICE*** - no datasource plugins have been loaded'
def test_field_listing(): def test_field_listing():
lyr = mapnik.Layer('test')
if 'shape' in mapnik.DatasourceCache.instance().plugin_names(): if 'shape' in mapnik.DatasourceCache.instance().plugin_names():
lyr.datasource = mapnik.Shapefile(file='../data/shp/poly.shp') ds = mapnik.Shapefile(file='../data/shp/poly.shp')
fields = lyr.datasource.fields() fields = ds.fields()
eq_(fields, ['AREA', 'EAS_ID', 'PRFEDEA']) eq_(fields, ['AREA', 'EAS_ID', 'PRFEDEA'])
eq_(ds.describe(),{'geometry_type': mapnik.DataGeometryType.Polygon, 'type': mapnik.DataType.Vector, 'name': 'shape', 'encoding': 'utf-8'})
def test_total_feature_count_shp(): def test_total_feature_count_shp():
lyr = mapnik.Layer('test')
if 'shape' in mapnik.DatasourceCache.instance().plugin_names(): if 'shape' in mapnik.DatasourceCache.instance().plugin_names():
lyr.datasource = mapnik.Shapefile(file='../data/shp/poly.shp') ds = mapnik.Shapefile(file='../data/shp/poly.shp')
features = lyr.datasource.all_features() features = ds.all_features()
num_feats = len(features) num_feats = len(features)
eq_(num_feats, 10) eq_(num_feats, 10)
def test_total_feature_count_json(): def test_total_feature_count_json():
lyr = mapnik.Layer('test')
if 'ogr' in mapnik.DatasourceCache.instance().plugin_names(): if 'ogr' in mapnik.DatasourceCache.instance().plugin_names():
lyr.datasource = mapnik.Ogr(file='../data/json/points.json',layer_by_index=0) ds = mapnik.Ogr(file='../data/json/points.json',layer_by_index=0)
features = lyr.datasource.all_features() eq_(ds.describe(),{'geometry_type': mapnik.DataGeometryType.Point, 'type': mapnik.DataType.Vector, 'name': 'ogr', 'encoding': 'utf-8'})
features = ds.all_features()
num_feats = len(features) num_feats = len(features)
eq_(num_feats, 5) eq_(num_feats, 5)
def test_sqlite_reading():
if 'sqlite' in mapnik.DatasourceCache.instance().plugin_names():
ds = mapnik.SQLite(file='../data/sqlite/world.sqlite',table_by_index=0)
eq_(ds.describe(),{'geometry_type': mapnik.DataGeometryType.Polygon, 'type': mapnik.DataType.Vector, 'name': 'sqlite', 'encoding': 'utf-8'})
features = ds.all_features()
num_feats = len(features)
eq_(num_feats, 245)
def test_reading_json_from_string(): def test_reading_json_from_string():
json = open('../data/json/points.json','r').read() json = open('../data/json/points.json','r').read()
lyr = mapnik.Layer('test')
if 'ogr' in mapnik.DatasourceCache.instance().plugin_names(): if 'ogr' in mapnik.DatasourceCache.instance().plugin_names():
lyr.datasource = mapnik.Ogr(file=json,layer_by_index=0) ds = mapnik.Ogr(file=json,layer_by_index=0)
features = lyr.datasource.all_features() features = ds.all_features()
num_feats = len(features) num_feats = len(features)
eq_(num_feats, 5) eq_(num_feats, 5)
def test_feature_envelope(): def test_feature_envelope():
lyr = mapnik.Layer('test')
if 'shape' in mapnik.DatasourceCache.instance().plugin_names(): if 'shape' in mapnik.DatasourceCache.instance().plugin_names():
lyr.datasource = mapnik.Shapefile(file='../data/shp/poly.shp') ds = mapnik.Shapefile(file='../data/shp/poly.shp')
features = lyr.datasource.all_features() features = ds.all_features()
for feat in features: for feat in features:
env = feat.envelope() env = feat.envelope()
contains = lyr.envelope().contains(env) contains = ds.envelope().contains(env)
eq_(contains, True) eq_(contains, True)
intersects = lyr.envelope().contains(env) intersects = ds.envelope().contains(env)
eq_(intersects, True) eq_(intersects, True)
def test_feature_attributes(): def test_feature_attributes():
lyr = mapnik.Layer('test')
if 'shape' in mapnik.DatasourceCache.instance().plugin_names(): if 'shape' in mapnik.DatasourceCache.instance().plugin_names():
lyr.datasource = mapnik.Shapefile(file='../data/shp/poly.shp') ds = mapnik.Shapefile(file='../data/shp/poly.shp')
features = lyr.datasource.all_features() features = ds.all_features()
feat = features[0] feat = features[0]
attrs = {'PRFEDEA': u'35043411', 'EAS_ID': 168, 'AREA': 215229.266} attrs = {'PRFEDEA': u'35043411', 'EAS_ID': 168, 'AREA': 215229.266}
eq_(feat.attributes, attrs) eq_(feat.attributes, attrs)
eq_(lyr.datasource.fields(),['AREA', 'EAS_ID', 'PRFEDEA']) eq_(ds.fields(),['AREA', 'EAS_ID', 'PRFEDEA'])
eq_(lyr.datasource.field_types(),['float','int','str']) eq_(ds.field_types(),['float','int','str'])
def test_ogr_layer_by_sql(): def test_ogr_layer_by_sql():
lyr = mapnik.Layer('test')
if 'ogr' in mapnik.DatasourceCache.instance().plugin_names(): if 'ogr' in mapnik.DatasourceCache.instance().plugin_names():
lyr.datasource = mapnik.Ogr(file='../data/shp/poly.shp', layer_by_sql='SELECT * FROM poly WHERE EAS_ID = 168') ds = mapnik.Ogr(file='../data/shp/poly.shp', layer_by_sql='SELECT * FROM poly WHERE EAS_ID = 168')
features = lyr.datasource.all_features() features = ds.all_features()
num_feats = len(features) num_feats = len(features)
eq_(num_feats, 1) eq_(num_feats, 1)

View file

@ -58,8 +58,8 @@ def test_adding_datasource_to_layer():
m.layers[0].datasource = ds m.layers[0].datasource = ds
# now ensure it is attached # now ensure it is attached
eq_(m.layers[0].datasource.name(),"shape") eq_(m.layers[0].datasource.describe()['name'],"shape")
eq_(lyr.datasource.name(),"shape") eq_(lyr.datasource.describe()['name'],"shape")
# and since we have now added a shapefile in spherical mercator, adjust the projection # and since we have now added a shapefile in spherical mercator, adjust the projection
lyr.srs = '+proj=merc +lon_0=0 +lat_ts=0 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs' lyr.srs = '+proj=merc +lon_0=0 +lat_ts=0 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs'

View file

@ -20,7 +20,7 @@ def call(cmd,silent=False):
stdin, stderr = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE).communicate() stdin, stderr = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE).communicate()
if not stderr: if not stderr:
return stdin.strip() return stdin.strip()
elif not silent: elif not silent and not 'NOTICE' in stderr:
raise RuntimeError(stderr.strip()) raise RuntimeError(stderr.strip())
def psql_can_connect(): def psql_can_connect():
@ -63,12 +63,23 @@ def createdb_and_dropdb_on_path():
print 'Notice: skipping postgis tests (createdb/dropdb)' print 'Notice: skipping postgis tests (createdb/dropdb)'
return False return False
insert_sql = """
INSERT INTO test(geom) values (GeomFromEWKT('SRID=4326;POINT(0 0)'));
INSERT INTO test(geom) values (GeomFromEWKT('SRID=4326;POINT(-2 2)'));
INSERT INTO test(geom) values (GeomFromEWKT('SRID=4326;MULTIPOINT(2 1,1 2)'));
INSERT INTO test(geom) values (GeomFromEWKT('SRID=4326;LINESTRING(0 0,1 1,1 2)'));
INSERT INTO test(geom) values (GeomFromEWKT('SRID=4326;MULTILINESTRING((1 0,0 1,3 2),(3 2,5 4))'));
INSERT INTO test(geom) values (GeomFromEWKT('SRID=4326;POLYGON((0 0,4 0,4 4,0 4,0 0),(1 1, 2 1, 2 2, 1 2,1 1))'));
INSERT INTO test(geom) values (GeomFromEWKT('SRID=4326;MULTIPOLYGON(((1 1,3 1,3 3,1 3,1 1),(1 1,2 1,2 2,1 2,1 1)), ((-1 -1,-1 -2,-2 -2,-2 -1,-1 -1)))'));
INSERT INTO test(geom) values (GeomFromEWKT('SRID=4326;GEOMETRYCOLLECTION(POLYGON((1 1, 2 1, 2 2, 1 2,1 1)),POINT(2 3),LINESTRING(2 3,3 4))'));
"""
def postgis_setup(): def postgis_setup():
call('dropdb %s' % MAPNIK_TEST_DBNAME,silent=True) call('dropdb %s' % MAPNIK_TEST_DBNAME,silent=True)
call('createdb -T %s %s' % (POSTGIS_TEMPLATE_DBNAME,MAPNIK_TEST_DBNAME),silent=False) call('createdb -T %s %s' % (POSTGIS_TEMPLATE_DBNAME,MAPNIK_TEST_DBNAME),silent=False)
call('shp2pgsql -s 3857 -g geom -W LATIN1 %s world_merc | psql -q %s' % (SHAPEFILE,MAPNIK_TEST_DBNAME), silent=True) call('shp2pgsql -s 3857 -g geom -W LATIN1 %s world_merc | psql -q %s' % (SHAPEFILE,MAPNIK_TEST_DBNAME), silent=True)
call('''psql %s -c "CREATE TABLE \"empty\" (key serial);SELECT AddGeometryColumn('','empty','geom','-1','GEOMETRY',4);"''' % MAPNIK_TEST_DBNAME,silent=True) call('''psql -q %s -c "CREATE TABLE \"empty\" (key serial);SELECT AddGeometryColumn('','empty','geom','-1','GEOMETRY',4);"''' % MAPNIK_TEST_DBNAME,silent=False)
call('''psql -q %s -c "create table test(gid serial PRIMARY KEY, geom geometry);%s"''' % (MAPNIK_TEST_DBNAME,insert_sql),silent=False)
def postgis_takedown(): def postgis_takedown():
pass pass
# fails as the db is in use: https://github.com/mapnik/mapnik/issues/960 # fails as the db is in use: https://github.com/mapnik/mapnik/issues/960
@ -98,6 +109,7 @@ if 'postgis' in mapnik.DatasourceCache.instance().plugin_names() \
eq_(feature['subregion'],29) eq_(feature['subregion'],29)
eq_(feature['lon'],-61.783) eq_(feature['lon'],-61.783)
eq_(feature['lat'],17.078) eq_(feature['lat'],17.078)
eq_(ds.describe()['geometry_type'],mapnik.DataGeometryType.Polygon)
def test_subquery(): def test_subquery():
ds = mapnik.PostGIS(dbname=MAPNIK_TEST_DBNAME,table='(select * from world_merc) as w') ds = mapnik.PostGIS(dbname=MAPNIK_TEST_DBNAME,table='(select * from world_merc) as w')
@ -115,6 +127,7 @@ if 'postgis' in mapnik.DatasourceCache.instance().plugin_names() \
eq_(feature['subregion'],29) eq_(feature['subregion'],29)
eq_(feature['lon'],-61.783) eq_(feature['lon'],-61.783)
eq_(feature['lat'],17.078) eq_(feature['lat'],17.078)
eq_(ds.describe()['geometry_type'],mapnik.DataGeometryType.Polygon)
ds = mapnik.PostGIS(dbname=MAPNIK_TEST_DBNAME,table='(select gid,geom,fips as _fips from world_merc) as w') ds = mapnik.PostGIS(dbname=MAPNIK_TEST_DBNAME,table='(select gid,geom,fips as _fips from world_merc) as w')
fs = ds.featureset() fs = ds.featureset()
@ -122,12 +135,39 @@ if 'postgis' in mapnik.DatasourceCache.instance().plugin_names() \
eq_(feature['gid'],1) eq_(feature['gid'],1)
eq_(feature['_fips'],u'AC') eq_(feature['_fips'],u'AC')
eq_(len(feature),2) eq_(len(feature),2)
eq_(ds.describe()['geometry_type'],mapnik.DataGeometryType.Polygon)
def test_empty_db(): def test_empty_db():
ds = mapnik.PostGIS(dbname=MAPNIK_TEST_DBNAME,table='empty') ds = mapnik.PostGIS(dbname=MAPNIK_TEST_DBNAME,table='empty')
fs = ds.featureset() fs = ds.featureset()
feature = fs.next() feature = fs.next()
eq_(feature,None) eq_(feature,None)
eq_(ds.describe()['geometry_type'],mapnik.DataGeometryType.Collection)
def test_geometry_detection():
ds = mapnik.PostGIS(dbname=MAPNIK_TEST_DBNAME,table='test',
geometry_field='geom')
eq_(ds.describe()['geometry_type'],mapnik.DataGeometryType.Collection)
ds = mapnik.PostGIS(dbname=MAPNIK_TEST_DBNAME,table='test',
geometry_field='geom',
row_limit=1)
eq_(ds.describe()['geometry_type'],mapnik.DataGeometryType.Point)
ds = mapnik.PostGIS(dbname=MAPNIK_TEST_DBNAME,table='test',
geometry_field='geom',
row_limit=2)
eq_(ds.describe()['geometry_type'],mapnik.DataGeometryType.Point)
ds = mapnik.PostGIS(dbname=MAPNIK_TEST_DBNAME,table='test',
geometry_field='geom',
row_limit=3)
eq_(ds.describe()['geometry_type'],mapnik.DataGeometryType.Point)
ds = mapnik.PostGIS(dbname=MAPNIK_TEST_DBNAME,table='test',
geometry_field='geom',
row_limit=4)
eq_(ds.describe()['geometry_type'],mapnik.DataGeometryType.Collection)
@raises(RuntimeError) @raises(RuntimeError)
def test_that_nonexistant_query_field_throws(**kwargs): def test_that_nonexistant_query_field_throws(**kwargs):