ensure all plugins report best guess at top level geometry_type using new descriptor attribute
This commit is contained in:
parent
967652efb6
commit
975afebd87
10 changed files with 301 additions and 16 deletions
|
@ -13,6 +13,7 @@
|
|||
#include <mapnik/geometry.hpp>
|
||||
#include <mapnik/memory_featureset.hpp>
|
||||
#include <mapnik/wkt/wkt_factory.hpp>
|
||||
#include <mapnik/util/geometry_to_type_str.hpp>
|
||||
#include <mapnik/ptree_helpers.hpp> // mapnik::boolean
|
||||
|
||||
// stl
|
||||
|
@ -830,6 +831,24 @@ void csv_datasource::parse_csv(T& stream,
|
|||
{
|
||||
if (!quiet_) std::clog << "CSV Plugin: could not parse any lines of data\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string g_type("");
|
||||
std::string prev_type("");
|
||||
boost::ptr_vector<mapnik::geometry_type> paths;
|
||||
unsigned num_features = features_.size();
|
||||
for (int i = 0; i < num_features; ++i)
|
||||
{
|
||||
mapnik::util::to_type_str(features_[i]->paths(),g_type);
|
||||
if (!prev_type.empty() && g_type != prev_type)
|
||||
{
|
||||
g_type = "collection";
|
||||
break;
|
||||
}
|
||||
prev_type = g_type;
|
||||
}
|
||||
desc_.set_geometry_type(g_type);
|
||||
}
|
||||
}
|
||||
|
||||
std::string csv_datasource::name()
|
||||
|
|
|
@ -212,6 +212,31 @@ void geos_datasource::bind() const
|
|||
}
|
||||
}
|
||||
|
||||
// get geometry type
|
||||
const int type = GEOSGeomTypeId(*geometry_);
|
||||
switch (type)
|
||||
{
|
||||
case GEOS_POINT:
|
||||
case GEOS_MULTIPOINT:
|
||||
desc_.set_geometry_type("point");
|
||||
break;
|
||||
case GEOS_LINESTRING:
|
||||
case GEOS_LINEARRING:
|
||||
case GEOS_MULTILINESTRING:
|
||||
desc_.set_geometry_type("linestring");
|
||||
break;
|
||||
case GEOS_POLYGON:
|
||||
case GEOS_MULTIPOLYGON:
|
||||
desc_.set_geometry_type("polygon");
|
||||
break;
|
||||
case GEOS_GEOMETRYCOLLECTION:
|
||||
desc_.set_geometry_type("collection");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (! extent_initialized_)
|
||||
{
|
||||
throw datasource_exception("GEOS Plugin: cannot determine extent for <wkt> geometry");
|
||||
|
|
|
@ -119,6 +119,8 @@ void kismet_datasource::bind() const
|
|||
{
|
||||
if (is_bound_) return;
|
||||
|
||||
desc_.set_geometry_type("point");
|
||||
|
||||
is_bound_ = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ private:
|
|||
unsigned int port_;
|
||||
int type_;
|
||||
std::string srs_;
|
||||
mapnik::layer_descriptor desc_;
|
||||
mutable mapnik::layer_descriptor desc_;
|
||||
boost::shared_ptr<boost::thread> kismet_thread;
|
||||
};
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
@ -265,6 +266,70 @@ void ogr_datasource::bind() const
|
|||
}
|
||||
#endif
|
||||
|
||||
// get geometry type
|
||||
// NOTE: wkbFlatten macro in ogr flattens 2.5d types into base 2d type
|
||||
switch (wkbFlatten(layer->GetGeomType()))
|
||||
{
|
||||
case wkbPoint:
|
||||
case wkbMultiPoint:
|
||||
desc_.set_geometry_type("point");
|
||||
break;
|
||||
case wkbLinearRing:
|
||||
case wkbLineString:
|
||||
case wkbMultiLineString:
|
||||
desc_.set_geometry_type("linestring");
|
||||
break;
|
||||
case wkbPolygon:
|
||||
case wkbMultiPolygon:
|
||||
desc_.set_geometry_type("polygon");
|
||||
break;
|
||||
case wkbGeometryCollection:
|
||||
desc_.set_geometry_type("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:
|
||||
desc_.set_geometry_type("point");
|
||||
break;
|
||||
case wkbLinearRing:
|
||||
case wkbLineString:
|
||||
case wkbMultiLineString:
|
||||
desc_.set_geometry_type("linestring");
|
||||
break;
|
||||
case wkbPolygon:
|
||||
case wkbMultiPolygon:
|
||||
desc_.set_geometry_type("polygon");
|
||||
break;
|
||||
case wkbGeometryCollection:
|
||||
desc_.set_geometry_type("collection");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// deal with attributes descriptions
|
||||
OGRFeatureDefn* def = layer->GetLayerDefn();
|
||||
if (def != 0)
|
||||
|
|
|
@ -123,6 +123,9 @@ void osm_datasource::bind() const
|
|||
extent_ = box2d<double>(b.w, b.s, b.e, b.n);
|
||||
}
|
||||
|
||||
// osm data is most likely a collection of geometry types
|
||||
desc_.set_geometry_type("collection");
|
||||
|
||||
is_bound_ = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
#include <mapnik/global.hpp>
|
||||
#include <mapnik/ptree_helpers.hpp>
|
||||
#include <mapnik/sql_utils.hpp>
|
||||
#include <mapnik/util/geometry_to_type_str.hpp>
|
||||
#include <mapnik/wkb.hpp>
|
||||
|
||||
// boost
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
@ -106,6 +108,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 +117,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,7 +147,7 @@ void postgis_datasource::bind() const
|
|||
if (!geometryColumn_.length() > 0 || srid_ == 0)
|
||||
{
|
||||
std::ostringstream s;
|
||||
s << "SELECT f_geometry_column, srid FROM ";
|
||||
s << "SELECT f_geometry_column, srid, lower(type) as type FROM ";
|
||||
s << GEOMETRY_COLUMNS <<" WHERE f_table_name='" << mapnik::sql_utils::unquote_double(geometry_table_) <<"'";
|
||||
|
||||
if (schema_.length() > 0)
|
||||
|
@ -161,7 +163,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");
|
||||
|
@ -177,6 +179,25 @@ void postgis_datasource::bind() const
|
|||
std::clog << "Postgis Plugin: SRID=" << rs->getValue("srid") << " " << ex.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
g_type = rs->getValue("type");
|
||||
if (boost::algorithm::contains(g_type,"line"))
|
||||
{
|
||||
g_type = "linestring";
|
||||
}
|
||||
else if (boost::algorithm::contains(g_type,"point"))
|
||||
{
|
||||
g_type = "point";
|
||||
}
|
||||
else if (boost::algorithm::contains(g_type,"polygon"))
|
||||
{
|
||||
g_type = "polygon";
|
||||
}
|
||||
else // geometry
|
||||
{
|
||||
g_type = "collection";
|
||||
}
|
||||
desc_.set_geometry_type(g_type);
|
||||
}
|
||||
rs->close();
|
||||
|
||||
|
@ -196,7 +217,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 +259,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 +347,55 @@ void postgis_datasource::bind() const
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
rs->close();
|
||||
|
||||
// fallback to querying first several features
|
||||
if (g_type.empty() && !geometryColumn_.empty())
|
||||
{
|
||||
s.str("");
|
||||
std::string g_type("");
|
||||
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";
|
||||
}
|
||||
else if (boost::algorithm::icontains(data,"point"))
|
||||
{
|
||||
g_type = "point";
|
||||
}
|
||||
else if (boost::algorithm::icontains(data,"polygon"))
|
||||
{
|
||||
g_type = "polygon";
|
||||
}
|
||||
else // geometry
|
||||
{
|
||||
g_type = "collection";
|
||||
break;
|
||||
}
|
||||
if (!prev_type.empty() && g_type != prev_type)
|
||||
{
|
||||
g_type = "collection";
|
||||
break;
|
||||
}
|
||||
prev_type = g_type;
|
||||
}
|
||||
desc_.set_geometry_type(g_type);
|
||||
}
|
||||
|
||||
is_bound_ = true;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -185,6 +185,35 @@ void shape_datasource::init(shape_io& shape) const
|
|||
int shape_type = shape.shp().read_ndr_integer();
|
||||
if (shape_type == shape_io::shape_multipatch)
|
||||
throw datasource_exception("Shape Plugin: shapefile multipatch type is not supported");
|
||||
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:
|
||||
{
|
||||
desc_.set_geometry_type("point");
|
||||
break;
|
||||
}
|
||||
case shape_io::shape_polyline:
|
||||
case shape_io::shape_polylinem:
|
||||
case shape_io::shape_polylinez:
|
||||
{
|
||||
desc_.set_geometry_type("linestring");
|
||||
break;
|
||||
}
|
||||
case shape_io::shape_polygon:
|
||||
case shape_io::shape_polygonm:
|
||||
case shape_io::shape_polygonz:
|
||||
{
|
||||
desc_.set_geometry_type("polygon");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
shape.shp().read_envelope(extent_);
|
||||
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
// mapnik
|
||||
#include <mapnik/ptree_helpers.hpp>
|
||||
#include <mapnik/sql_utils.hpp>
|
||||
#include <mapnik/util/geometry_to_type_str.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,38 @@ void sqlite_datasource::bind() const
|
|||
throw datasource_exception(s.str());
|
||||
}
|
||||
}
|
||||
|
||||
// finally, get geometry type by querying first feature
|
||||
std::ostringstream s;
|
||||
std::string g_type("");
|
||||
std::string prev_type("");
|
||||
boost::ptr_vector<mapnik::geometry_type> paths;
|
||||
|
||||
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());
|
||||
while (rs->is_valid() && rs->step_next())
|
||||
{
|
||||
int size;
|
||||
const char* data = (const char*) rs->column_blob(0, size);
|
||||
if (data)
|
||||
{
|
||||
mapnik::geometry_utils::from_wkb(paths, data, size, mapnik::wkbAuto);
|
||||
mapnik::util::to_type_str(paths,g_type);
|
||||
if (!prev_type.empty() && g_type != prev_type)
|
||||
{
|
||||
g_type = "collection";
|
||||
break;
|
||||
}
|
||||
prev_type = g_type;
|
||||
}
|
||||
}
|
||||
desc_.set_geometry_type(g_type);
|
||||
|
||||
is_bound_ = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -34,6 +34,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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue