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):
def describe(self):
return Describe(self)
def all_features(self,fields=None):
query = Query(self.envelope())
attributes = fields or self.fields()
@ -710,7 +707,6 @@ __all__ = [
'SQLite',
'Osm',
'Kismet',
'Describe',
# version and environment
'mapnik_version_string',
'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);
}
std::string describe(boost::shared_ptr<mapnik::datasource> const& ds)
boost::python::dict describe(boost::shared_ptr<mapnik::datasource> const& ds)
{
std::stringstream ss;
if (ds)
{
ss << ds->get_descriptor() << "\n";
}
else
{
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::dict description;
mapnik::layer_descriptor ld = ds->get_descriptor();
description["type"] = ds->type();
description["name"] = ld.get_name();
description["geometry_type"] = ds->get_geometry_type();
description["encoding"] = ld.get_encoding();
return description;
}
boost::python::list fields(boost::shared_ptr<mapnik::datasource> const& ds)
@ -163,23 +148,34 @@ void export_datasource()
{
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>,
boost::noncopyable>("Datasource",no_init)
.def("type",&datasource::type)
.def("geometry_type",&datasource::get_geometry_type)
.def("describe",&describe)
.def("envelope",&datasource::envelope)
.def("descriptor",&datasource::get_descriptor) //todo
.def("features",&datasource::features)
.def("bind",&datasource::bind)
.def("fields",&fields)
.def("field_types",&field_types)
.def("encoding",&encoding) //todo expose as property
.def("name",&name)
.def("features_at_point",&datasource::features_at_point)
.def("params",&datasource::params,return_value_policy<copy_const_reference>(),
"The configuration parameters of the data source. "
"These vary depending on the type of data source.")
;
def("Describe",&describe);
def("CreateDatasource",&create_datasource);
class_<point_datasource, bases<datasource>, boost::noncopyable>("PointDatasource", init<>())

View file

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

View file

@ -85,6 +85,7 @@ void export_label_collision_detector();
#include <mapnik/save_map.hpp>
#include "python_grid_utils.hpp"
#include "mapnik_value_converter.hpp"
#include "python_optional.hpp"
#if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO)
#include <pycairo.h>
@ -630,6 +631,9 @@ BOOST_PYTHON_MODULE(_mapnik)
def("has_cairo", &has_cairo, "Get cairo library 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::path_expression_ptr>();
to_python_converter<mapnik::value_holder,mapnik_param_to_python>();

View file

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

View file

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

View file

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

View file

@ -39,8 +39,8 @@
namespace mapnik
{
typedef boost::variant<value_null,int,double,std::string> value_holder;
typedef std::pair<const std::string, value_holder> parameter;
typedef std::map<const std::string, value_holder> param_map;
typedef std::pair<std::string, value_holder> parameter;
typedef std::map<std::string, value_holder> param_map;
template <typename T>
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/memory_featureset.hpp>
#include <mapnik/wkt/wkt_factory.hpp>
#include <mapnik/util/geometry_to_ds_type.hpp>
#include <mapnik/ptree_helpers.hpp> // mapnik::boolean
// stl
@ -837,7 +838,7 @@ std::string csv_datasource::name()
return "csv";
}
int csv_datasource::type() const
datasource::datasource_t csv_datasource::type() const
{
return datasource::Vector;
}
@ -849,6 +850,29 @@ mapnik::box2d<double> csv_datasource::envelope() const
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
{
if (!is_bound_) bind();

View file

@ -12,11 +12,12 @@ class csv_datasource : public mapnik::datasource
public:
csv_datasource(mapnik::parameters const& params, bool bind=true);
virtual ~csv_datasource ();
int type() const;
mapnik::datasource::datasource_t type() const;
static std::string name();
mapnik::featureset_ptr features(mapnik::query const& q) const;
mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const;
mapnik::box2d<double> envelope() const;
boost::optional<mapnik::datasource::geometry_t> get_geometry_type() const;
mapnik::layer_descriptor get_descriptor() const;
void bind() const;
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;
}
@ -214,6 +214,11 @@ box2d<double> gdal_datasource::envelope() const
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
{
return desc_;

View file

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

View file

@ -225,7 +225,7 @@ std::string geos_datasource::name()
return "geos";
}
int geos_datasource::type() const
mapnik::datasource::datasource_t geos_datasource::type() const
{
return type_;
}
@ -237,6 +237,38 @@ box2d<double> geos_datasource::envelope() const
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
{
if (! is_bound_) bind();

View file

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

View file

@ -131,7 +131,7 @@ std::string kismet_datasource::name()
return "kismet";
}
int kismet_datasource::type() const
mapnik::datasource::datasource_t kismet_datasource::type() const
{
return type_;
}
@ -142,6 +142,11 @@ box2d<double> kismet_datasource::envelope() const
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
{
return desc_;

View file

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

View file

@ -351,7 +351,7 @@ std::string occi_datasource::name()
return "occi";
}
int occi_datasource::type() const
mapnik::datasource::datasource_t occi_datasource::type() const
{
return type_;
}
@ -474,6 +474,14 @@ box2d<double> occi_datasource::envelope() const
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
{
if (! is_bound_) bind();

View file

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

View file

@ -28,6 +28,7 @@
#include "ogr_datasource.hpp"
#include "ogr_featureset.hpp"
#include "ogr_index_featureset.hpp"
#include "ogr_feature_ptr.hpp"
// mapnik
#include <mapnik/ptree_helpers.hpp>
@ -331,7 +332,7 @@ std::string ogr_datasource::name()
return "ogr";
}
int ogr_datasource::type() const
mapnik::datasource::datasource_t ogr_datasource::type() const
{
return type_;
}
@ -342,6 +343,79 @@ box2d<double> ogr_datasource::envelope() const
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
{
if (! is_bound_) bind();

View file

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

View file

@ -137,7 +137,7 @@ std::string osm_datasource::name()
return "osm";
}
int osm_datasource::type() const
mapnik::datasource::datasource_t osm_datasource::type() const
{
return type_;
}
@ -189,3 +189,9 @@ box2d<double> osm_datasource::envelope() const
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:
osm_datasource(const parameters& params, bool bind = true);
virtual ~osm_datasource();
int type() const;
mapnik::datasource::datasource_t type() const;
featureset_ptr features(const query& q) const;
featureset_ptr features_at_point(coord2d const& pt) const;
box2d<double> envelope() const;
boost::optional<mapnik::datasource::geometry_t> get_geometry_type() const;
layer_descriptor get_descriptor() const;
static std::string name();
void bind() const;
private:
mutable box2d<double> extent_;
mutable osm_dataset* osm_data_;
int type_;
mapnik::datasource::datasource_t type_;
mutable layer_descriptor desc_;
// no copying
osm_datasource(const osm_datasource&);

View file

@ -106,6 +106,8 @@ void postgis_datasource::bind() const
ConnectionManager *mgr=ConnectionManager::instance();
mgr->registerPool(creator_, *initial_size, *max_size);
std::string g_type;
shared_ptr<Pool<Connection,ConnectionCreator> > pool=mgr->getPool(creator_.id());
if (pool)
{
@ -113,8 +115,6 @@ void postgis_datasource::bind() const
if (conn && conn->isOK())
{
is_bound_ = true;
PoolGuard<shared_ptr<Connection>,
shared_ptr<Pool<Connection,ConnectionCreator> > > guard(conn,pool);
@ -145,14 +145,20 @@ void postgis_datasource::bind() const
if (!geometryColumn_.length() > 0 || srid_ == 0)
{
std::ostringstream s;
s << "SELECT f_geometry_column, srid FROM ";
s << GEOMETRY_COLUMNS <<" WHERE f_table_name='" << mapnik::sql_utils::unquote_double(geometry_table_) <<"'";
s << "SELECT f_geometry_column, srid 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_) << "'";
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_) << "'";
s << " AND f_geometry_column='"
<< mapnik::sql_utils::unquote_double(geometry_field_)
<< "'";
/*
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())
{
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())
{
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();
bool found_key_field = false;
for (int i=0;i<count;++i)
@ -326,7 +332,11 @@ void postgis_datasource::bind() const
}
}
}
rs->close();
is_bound_ = true;
}
}
}
@ -336,7 +346,7 @@ std::string postgis_datasource::name()
return "postgis";
}
int postgis_datasource::type() const
mapnik::datasource::datasource_t postgis_datasource::type() const
{
return type_;
}
@ -686,6 +696,118 @@ box2d<double> postgis_datasource::envelope() const
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()
{
if (is_bound_ && !persist_connection_)

View file

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

View file

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

View file

@ -36,7 +36,7 @@ class rasterlite_datasource : public mapnik::datasource
public:
rasterlite_datasource(mapnik::parameters const& params, bool bind = true);
virtual ~rasterlite_datasource ();
int type() const;
mapnik::datasource::datasource_t type() const;
static std::string name();
mapnik::featureset_ptr features(mapnik::query const& q) 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());
}
int shape_type = shape.shp().read_ndr_integer();
if (shape_type == shape_io::shape_multipatch)
shape_type_ = static_cast<shape_io::shapeType>(shape.shp().read_ndr_integer());
if (shape_type_ == shape_io::shape_multipatch)
throw datasource_exception("Shape Plugin: shapefile multipatch type is not supported");
shape.shp().read_envelope(extent_);
@ -229,7 +229,7 @@ std::string shape_datasource::name()
return "shape";
}
int shape_datasource::type() const
datasource::datasource_t shape_datasource::type() const
{
return type_;
}
@ -314,3 +314,39 @@ box2d<double> shape_datasource::envelope() const
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);
virtual ~shape_datasource();
int type() const;
datasource::datasource_t type() const;
static std::string name();
featureset_ptr features(const query& q) const;
featureset_ptr features_at_point(coord2d const& pt) const;
box2d<double> envelope() const;
boost::optional<mapnik::datasource::geometry_t> get_geometry_type() const;
layer_descriptor get_descriptor() const;
void bind() const;
private:
@ -57,9 +58,10 @@ private:
shape_datasource& operator=(const shape_datasource&);
void init(shape_io& shape) const;
private:
int type_;
datasource::datasource_t type_;
std::string shape_name_;
mutable boost::shared_ptr<shape_io> shape_;
mutable shape_io::shapeType shape_type_;
mutable long file_length_;
mutable box2d<double> extent_;
mutable bool indexed_;

View file

@ -71,7 +71,7 @@ void shape_io::move_to(int pos)
shp_.seek(pos);
id_ = 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)
{
@ -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_;
}

View file

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

View file

@ -28,6 +28,8 @@
// mapnik
#include <mapnik/ptree_helpers.hpp>
#include <mapnik/sql_utils.hpp>
#include <mapnik/util/geometry_to_ds_type.hpp>
#include <mapnik/wkb.hpp>
// boost
#include <boost/algorithm/string.hpp>
@ -69,16 +71,12 @@ sqlite_datasource::sqlite_datasource(parameters const& params, bool bind)
/* TODO
- throw if no primary key but spatial index is present?
- remove auto-indexing
- if spatialite - leverage more of the metadata for geometry type detection
*/
boost::optional<std::string> file = params_.get<std::string>("file");
if (! file) throw datasource_exception("Sqlite Plugin: missing <file> parameter");
if (table_.empty())
{
throw mapnik::datasource_exception("Sqlite Plugin: missing <table> parameter");
}
if (bind)
{
this->bind();
@ -147,6 +145,44 @@ void sqlite_datasource::bind() const
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())
{
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_
for (std::vector<std::string>::const_iterator iter = init_statements_.begin();
iter != init_statements_.end(); ++iter)
@ -188,7 +221,11 @@ void sqlite_datasource::bind() const
std::ostringstream s;
std::string query = populate_tokens(table_);
s << "SELECT " << fields_ << " FROM (" << query << ") LIMIT 1";
found_types_via_subquery = sqlite_utils::detect_types_from_subquery(s.str(),geometry_field_,desc_,dataset_);
found_types_via_subquery = sqlite_utils::detect_types_from_subquery(
s.str(),
geometry_field_,
desc_,
dataset_);
}
// TODO - consider removing this
@ -328,6 +365,7 @@ void sqlite_datasource::bind() const
throw datasource_exception(s.str());
}
}
is_bound_ = true;
}
@ -434,7 +472,7 @@ std::string sqlite_datasource::name()
return "sqlite";
}
int sqlite_datasource::type() const
mapnik::datasource::datasource_t sqlite_datasource::type() const
{
return type_;
}
@ -446,6 +484,53 @@ box2d<double> sqlite_datasource::envelope() const
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
{
if (! is_bound_) bind();

View file

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

View file

@ -12,8 +12,7 @@ using mapnik::parameters;
DATASOURCE_PLUGIN(hello_datasource)
hello_datasource::hello_datasource(parameters const& params, bool bind)
: datasource(params),
type_(datasource::Vector),
: datasource(params)
desc_(*params_.get<std::string>("type"), *params_.get<std::string>("encoding","utf-8")),
extent_()
{
@ -34,6 +33,10 @@ 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;
}
@ -47,9 +50,9 @@ std::string hello_datasource::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
@ -59,6 +62,11 @@ mapnik::box2d<double> hello_datasource::envelope() const
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
{
if (!is_bound_) bind();

View file

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

View file

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

View file

@ -69,7 +69,7 @@ void memory_datasource::push(feature_ptr feature)
features_.push_back(feature);
}
int memory_datasource::type() const
datasource::datasource_t memory_datasource::type() const
{
return datasource::Vector;
}
@ -96,6 +96,12 @@ box2d<double> memory_datasource::envelope() const
std::for_each(features_.begin(),features_.end(),func);
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
{
@ -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_id_;
geometry_type * pt = new geometry_type(Point);
geometry_type * pt = new geometry_type(mapnik::Point);
pt->move_to(x,y);
feature->add_geometry(pt);
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}
eq_(feat.attributes,attr)
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):
ds = get_csv_ds('blank_rows.csv')
eq_(ds.fields(),['x','y','name'])
eq_(ds.field_types(),['int','int','str'])
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):
ds = get_csv_ds('empty_rows.csv')
@ -75,6 +77,7 @@ if 'csv' in mapnik.DatasourceCache.instance().plugin_names():
eq_(len(feat),10)
eq_(feat['empty_column'],u'')
feat = fs.next()
eq_(ds.describe(),{'geometry_type': mapnik.DataGeometryType.Point, 'type': mapnik.DataType.Vector, 'name': 'csv', 'encoding': 'utf-8'})
def test_slashes(**kwargs):
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[1].attributes,{'x':1,'y':4,'name':u'b/b'})
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):
ds = get_csv_ds('wkt.csv')
@ -92,24 +96,25 @@ if 'csv' in mapnik.DatasourceCache.instance().plugin_names():
fs = ds.all_features()
#import pdb;pdb.set_trace()
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_(fs[1].geometries()[0].type(),mapnik.GeometryType.LineString)
eq_(fs[1].geometries()[0].type(),mapnik.DataGeometryType.LineString)
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_(fs[3].geometries()[0].type(),mapnik.GeometryType.Polygon)
eq_(fs[3].geometries()[0].type(),mapnik.DataGeometryType.Polygon)
# tests assuming we want to flatten geometries
# ideally we should not have to:
# https://github.com/mapnik/mapnik/issues?labels=multigeom+robustness&sort=created&direction=desc&state=open&page=1
eq_(len(fs[4].geometries()),4)
eq_(fs[4].geometries()[0].type(),mapnik.GeometryType.Point)
eq_(fs[4].geometries()[0].type(),mapnik.DataGeometryType.Point)
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_(fs[6].geometries()[0].type(),mapnik.GeometryType.Polygon)
eq_(fs[6].geometries()[0].type(),mapnik.DataGeometryType.Polygon)
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):
@ -119,6 +124,7 @@ if 'csv' in mapnik.DatasourceCache.instance().plugin_names():
fs = ds.featureset()
feat = fs.next()
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):
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[3]['label'],"5,0")
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):
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['y'],10)
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):
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['y'],10)
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):
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['y'],48)
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):
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['y'],0)
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):
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['y'],0)
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):
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['null'],'')
eq_(feat['boolean'],'false')
eq_(ds.describe(),{'geometry_type': mapnik.DataGeometryType.Point, 'type': mapnik.DataType.Vector, 'name': 'csv', 'encoding': 'utf-8'})
@raises(RuntimeError)
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
query.add_property_name('bogus')
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):
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['y'],0)
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__":
setup()

View file

@ -15,65 +15,68 @@ def test_that_datasources_exist():
print '***NOTICE*** - no datasource plugins have been loaded'
def test_field_listing():
lyr = mapnik.Layer('test')
if 'shape' in mapnik.DatasourceCache.instance().plugin_names():
lyr.datasource = mapnik.Shapefile(file='../data/shp/poly.shp')
fields = lyr.datasource.fields()
ds = mapnik.Shapefile(file='../data/shp/poly.shp')
fields = ds.fields()
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():
lyr = mapnik.Layer('test')
if 'shape' in mapnik.DatasourceCache.instance().plugin_names():
lyr.datasource = mapnik.Shapefile(file='../data/shp/poly.shp')
features = lyr.datasource.all_features()
ds = mapnik.Shapefile(file='../data/shp/poly.shp')
features = ds.all_features()
num_feats = len(features)
eq_(num_feats, 10)
def test_total_feature_count_json():
lyr = mapnik.Layer('test')
if 'ogr' in mapnik.DatasourceCache.instance().plugin_names():
lyr.datasource = mapnik.Ogr(file='../data/json/points.json',layer_by_index=0)
features = lyr.datasource.all_features()
ds = mapnik.Ogr(file='../data/json/points.json',layer_by_index=0)
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)
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():
json = open('../data/json/points.json','r').read()
lyr = mapnik.Layer('test')
if 'ogr' in mapnik.DatasourceCache.instance().plugin_names():
lyr.datasource = mapnik.Ogr(file=json,layer_by_index=0)
features = lyr.datasource.all_features()
ds = mapnik.Ogr(file=json,layer_by_index=0)
features = ds.all_features()
num_feats = len(features)
eq_(num_feats, 5)
def test_feature_envelope():
lyr = mapnik.Layer('test')
if 'shape' in mapnik.DatasourceCache.instance().plugin_names():
lyr.datasource = mapnik.Shapefile(file='../data/shp/poly.shp')
features = lyr.datasource.all_features()
ds = mapnik.Shapefile(file='../data/shp/poly.shp')
features = ds.all_features()
for feat in features:
env = feat.envelope()
contains = lyr.envelope().contains(env)
contains = ds.envelope().contains(env)
eq_(contains, True)
intersects = lyr.envelope().contains(env)
intersects = ds.envelope().contains(env)
eq_(intersects, True)
def test_feature_attributes():
lyr = mapnik.Layer('test')
if 'shape' in mapnik.DatasourceCache.instance().plugin_names():
lyr.datasource = mapnik.Shapefile(file='../data/shp/poly.shp')
features = lyr.datasource.all_features()
ds = mapnik.Shapefile(file='../data/shp/poly.shp')
features = ds.all_features()
feat = features[0]
attrs = {'PRFEDEA': u'35043411', 'EAS_ID': 168, 'AREA': 215229.266}
eq_(feat.attributes, attrs)
eq_(lyr.datasource.fields(),['AREA', 'EAS_ID', 'PRFEDEA'])
eq_(lyr.datasource.field_types(),['float','int','str'])
eq_(ds.fields(),['AREA', 'EAS_ID', 'PRFEDEA'])
eq_(ds.field_types(),['float','int','str'])
def test_ogr_layer_by_sql():
lyr = mapnik.Layer('test')
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')
features = lyr.datasource.all_features()
ds = mapnik.Ogr(file='../data/shp/poly.shp', layer_by_sql='SELECT * FROM poly WHERE EAS_ID = 168')
features = ds.all_features()
num_feats = len(features)
eq_(num_feats, 1)

View file

@ -58,8 +58,8 @@ def test_adding_datasource_to_layer():
m.layers[0].datasource = ds
# now ensure it is attached
eq_(m.layers[0].datasource.name(),"shape")
eq_(lyr.datasource.name(),"shape")
eq_(m.layers[0].datasource.describe()['name'],"shape")
eq_(lyr.datasource.describe()['name'],"shape")
# 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'

View file

@ -20,7 +20,7 @@ def call(cmd,silent=False):
stdin, stderr = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE).communicate()
if not stderr:
return stdin.strip()
elif not silent:
elif not silent and not 'NOTICE' in stderr:
raise RuntimeError(stderr.strip())
def psql_can_connect():
@ -63,12 +63,23 @@ def createdb_and_dropdb_on_path():
print 'Notice: skipping postgis tests (createdb/dropdb)'
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():
call('dropdb %s' % MAPNIK_TEST_DBNAME,silent=True)
call('createdb -T %s %s' % (POSTGIS_TEMPLATE_DBNAME,MAPNIK_TEST_DBNAME),silent=False)
call('shp2pgsql -s 3857 -g geom -W LATIN1 %s world_merc | psql -q %s' % (SHAPEFILE,MAPNIK_TEST_DBNAME), silent=True)
call('''psql %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():
pass
# 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['lon'],-61.783)
eq_(feature['lat'],17.078)
eq_(ds.describe()['geometry_type'],mapnik.DataGeometryType.Polygon)
def test_subquery():
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['lon'],-61.783)
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')
fs = ds.featureset()
@ -122,12 +135,39 @@ if 'postgis' in mapnik.DatasourceCache.instance().plugin_names() \
eq_(feature['gid'],1)
eq_(feature['_fips'],u'AC')
eq_(len(feature),2)
eq_(ds.describe()['geometry_type'],mapnik.DataGeometryType.Polygon)
def test_empty_db():
ds = mapnik.PostGIS(dbname=MAPNIK_TEST_DBNAME,table='empty')
fs = ds.featureset()
feature = fs.next()
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)
def test_that_nonexistant_query_field_throws(**kwargs):