postgis.input - add support for TWKB (https://github.com/TWKB/Specification/blob/master/twkb.md) via https://github.com/CartoDB/mapnik/tree/2.3.x.cartodb ref #3355
This commit is contained in:
parent
2204a983c6
commit
7d4f894d98
4 changed files with 122 additions and 20 deletions
|
@ -88,6 +88,17 @@ postgis_datasource::postgis_datasource(parameters const& params)
|
||||||
extent_from_subquery_(*params.get<mapnik::boolean_type>("extent_from_subquery", false)),
|
extent_from_subquery_(*params.get<mapnik::boolean_type>("extent_from_subquery", false)),
|
||||||
max_async_connections_(*params_.get<mapnik::value_integer>("max_async_connection", 1)),
|
max_async_connections_(*params_.get<mapnik::value_integer>("max_async_connection", 1)),
|
||||||
asynchronous_request_(false),
|
asynchronous_request_(false),
|
||||||
|
twkb_encoding_(false),
|
||||||
|
twkb_rounding_adjustment_(*params_.get<mapnik::value_double>("twkb_rounding_adjustment", 0.0)),
|
||||||
|
simplify_snap_ratio_(*params_.get<mapnik::value_double>("simplify_snap_ratio", 1.0/40.0)),
|
||||||
|
// 1/20 of pixel seems to be a good compromise to avoid
|
||||||
|
// drop of collapsed polygons.
|
||||||
|
// See https://github.com/mapnik/mapnik/issues/1639
|
||||||
|
// See http://trac.osgeo.org/postgis/ticket/2093
|
||||||
|
simplify_dp_ratio_(*params_.get<mapnik::value_double>("simplify_dp_ratio", 1.0/20.0)),
|
||||||
|
simplify_prefilter_(*params_.get<mapnik::value_double>("simplify_prefilter", 0.0)),
|
||||||
|
simplify_dp_preserve_(false),
|
||||||
|
simplify_clip_resolution_(*params_.get<mapnik::value_double>("simplify_clip_resolution", 0.0)),
|
||||||
// TODO - use for known tokens too: "(@\\w+|!\\w+!)"
|
// TODO - use for known tokens too: "(@\\w+|!\\w+!)"
|
||||||
pattern_(boost::regex("(@\\w+)",boost::regex::normal | boost::regbase::icase)),
|
pattern_(boost::regex("(@\\w+)",boost::regex::normal | boost::regbase::icase)),
|
||||||
// params below are for testing purposes only and may be removed at any time
|
// params below are for testing purposes only and may be removed at any time
|
||||||
|
@ -130,6 +141,12 @@ postgis_datasource::postgis_datasource(parameters const& params)
|
||||||
boost::optional<mapnik::boolean_type> simplify_opt = params.get<mapnik::boolean_type>("simplify_geometries", false);
|
boost::optional<mapnik::boolean_type> simplify_opt = params.get<mapnik::boolean_type>("simplify_geometries", false);
|
||||||
simplify_geometries_ = simplify_opt && *simplify_opt;
|
simplify_geometries_ = simplify_opt && *simplify_opt;
|
||||||
|
|
||||||
|
boost::optional<mapnik::boolean_type> twkb_opt = params.get<mapnik::boolean_type>("twkb_encoding", false);
|
||||||
|
twkb_encoding_ = twkb_opt && *twkb_opt;
|
||||||
|
|
||||||
|
boost::optional<mapnik::boolean_type> simplify_preserve_opt = params.get<mapnik::boolean_type>("simplify_dp_preserve", false);
|
||||||
|
simplify_dp_preserve_ = simplify_preserve_opt && *simplify_preserve_opt;
|
||||||
|
|
||||||
ConnectionManager::instance().registerPool(creator_, *initial_size, pool_max_size_);
|
ConnectionManager::instance().registerPool(creator_, *initial_size, pool_max_size_);
|
||||||
CnxPool_ptr pool = ConnectionManager::instance().getPool(creator_.id());
|
CnxPool_ptr pool = ConnectionManager::instance().getPool(creator_.id());
|
||||||
if (pool)
|
if (pool)
|
||||||
|
@ -794,25 +811,91 @@ featureset_ptr postgis_datasource::features_with_context(query const& q,processo
|
||||||
|
|
||||||
const double px_gw = 1.0 / std::get<0>(q.resolution());
|
const double px_gw = 1.0 / std::get<0>(q.resolution());
|
||||||
const double px_gh = 1.0 / std::get<1>(q.resolution());
|
const double px_gh = 1.0 / std::get<1>(q.resolution());
|
||||||
|
const double px_sz = std::min(px_gw, px_gh);
|
||||||
|
|
||||||
s << "SELECT ST_AsBinary(";
|
if (twkb_encoding_)
|
||||||
|
{
|
||||||
|
// This will only work against PostGIS 2.2, or a back-patched version
|
||||||
|
// that has (a) a ST_Simplify with a "preserve collapsed" flag and
|
||||||
|
// (b) a ST_RemoveRepeatedPoints with a tolerance parameter and
|
||||||
|
// (c) a ST_AsTWKB implementation
|
||||||
|
|
||||||
if (simplify_geometries_) {
|
// What number of decimals of rounding does the pixel size imply?
|
||||||
s << "ST_Simplify(";
|
const int twkb_rounding = -1 * std::lround(log10(px_sz) + twkb_rounding_adjustment_) + 1;
|
||||||
|
// And what's that in map units?
|
||||||
|
const double twkb_tolerance = pow(10.0, -1.0 * twkb_rounding);
|
||||||
|
|
||||||
|
s << "SELECT ST_AsTWKB(";
|
||||||
|
s << "ST_Simplify(";
|
||||||
|
s << "ST_RemoveRepeatedPoints(";
|
||||||
|
|
||||||
|
if (simplify_clip_resolution_ > 0.0 && simplify_clip_resolution_ > px_sz)
|
||||||
|
{
|
||||||
|
s << "ST_ClipByBox2D(";
|
||||||
|
}
|
||||||
|
s << "\"" << geometryColumn_ << "\"";
|
||||||
|
|
||||||
|
// ! ST_ClipByBox2D()
|
||||||
|
if (simplify_clip_resolution_ > 0.0 && simplify_clip_resolution_ > px_sz)
|
||||||
|
{
|
||||||
|
s << "," << sql_bbox(box) << ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
// ! ST_RemoveRepeatedPoints()
|
||||||
|
s << "," << twkb_tolerance << ")";
|
||||||
|
// ! ST_Simplify(), with parameter to keep collapsed geometries
|
||||||
|
s << "," << twkb_tolerance << ",true)";
|
||||||
|
// ! ST_TWKB()
|
||||||
|
s << "," << twkb_rounding << ") AS geom";
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
s << "SELECT ST_AsBinary(";
|
||||||
|
if (simplify_geometries_)
|
||||||
|
{
|
||||||
|
s << "ST_Simplify(";
|
||||||
|
}
|
||||||
|
if (simplify_clip_resolution_ > 0.0 && simplify_clip_resolution_ > px_sz)
|
||||||
|
{
|
||||||
|
s << "ST_ClipByBox2D(";
|
||||||
|
}
|
||||||
|
if (simplify_geometries_ && simplify_snap_ratio_ > 0.0)
|
||||||
|
{
|
||||||
|
s<< "ST_SnapToGrid(";
|
||||||
|
}
|
||||||
|
|
||||||
s << "\"" << geometryColumn_ << "\"";
|
// Geometry column!
|
||||||
|
s << "\"" << geometryColumn_ << "\"";
|
||||||
|
|
||||||
if (simplify_geometries_) {
|
// ! ST_SnapToGrid()
|
||||||
// 1/20 of pixel seems to be a good compromise to avoid
|
if (simplify_geometries_ && simplify_snap_ratio_ > 0.0)
|
||||||
// drop of collapsed polygons.
|
{
|
||||||
// See https://github.com/mapnik/mapnik/issues/1639
|
const double tolerance = px_sz * simplify_snap_ratio_;
|
||||||
const double tolerance = std::min(px_gw, px_gh) / 20.0;
|
s << "," << tolerance << ")";
|
||||||
s << ", " << tolerance << ")";
|
}
|
||||||
|
|
||||||
|
// ! ST_ClipByBox2D()
|
||||||
|
if (simplify_clip_resolution_ > 0.0 && simplify_clip_resolution_ > px_sz)
|
||||||
|
{
|
||||||
|
s << "," << sql_bbox(box) << ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
// ! ST_Simplify()
|
||||||
|
if (simplify_geometries_)
|
||||||
|
{
|
||||||
|
const double tolerance = px_sz * simplify_dp_ratio_;
|
||||||
|
s << ", " << tolerance;
|
||||||
|
// Add parameter to ST_Simplify to keep collapsed geometries
|
||||||
|
if (simplify_dp_preserve_)
|
||||||
|
{
|
||||||
|
s << ", true";
|
||||||
|
}
|
||||||
|
s << ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
// ! ST_AsBinary()
|
||||||
|
s << ") AS geom";
|
||||||
}
|
}
|
||||||
|
|
||||||
s << ") AS geom";
|
|
||||||
|
|
||||||
mapnik::context_ptr ctx = std::make_shared<mapnik::context_type>();
|
mapnik::context_ptr ctx = std::make_shared<mapnik::context_type>();
|
||||||
std::set<std::string> const& props = q.property_names();
|
std::set<std::string> const& props = q.property_names();
|
||||||
std::set<std::string>::const_iterator pos = props.begin();
|
std::set<std::string>::const_iterator pos = props.begin();
|
||||||
|
@ -854,7 +937,8 @@ featureset_ptr postgis_datasource::features_with_context(query const& q,processo
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<IResultSet> rs = get_resultset(conn, s.str(), pool, proc_ctx);
|
std::shared_ptr<IResultSet> rs = get_resultset(conn, s.str(), pool, proc_ctx);
|
||||||
return std::make_shared<postgis_featureset>(rs, ctx, desc_.get_encoding(), !key_field_.empty(), key_field_as_attribute_);
|
return std::make_shared<postgis_featureset>(rs, ctx, desc_.get_encoding(), !key_field_.empty(),
|
||||||
|
key_field_as_attribute_, twkb_encoding_);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -941,7 +1025,8 @@ featureset_ptr postgis_datasource::features_at_point(coord2d const& pt, double t
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<IResultSet> rs = get_resultset(conn, s.str(), pool);
|
std::shared_ptr<IResultSet> rs = get_resultset(conn, s.str(), pool);
|
||||||
return std::make_shared<postgis_featureset>(rs, ctx, desc_.get_encoding(), !key_field_.empty(), key_field_as_attribute_);
|
return std::make_shared<postgis_featureset>(rs, ctx, desc_.get_encoding(), !key_field_.empty(),
|
||||||
|
key_field_as_attribute_, twkb_encoding_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -119,6 +119,13 @@ private:
|
||||||
bool estimate_extent_;
|
bool estimate_extent_;
|
||||||
int max_async_connections_;
|
int max_async_connections_;
|
||||||
bool asynchronous_request_;
|
bool asynchronous_request_;
|
||||||
|
bool twkb_encoding_;
|
||||||
|
mapnik::value_double twkb_rounding_adjustment_;
|
||||||
|
mapnik::value_double simplify_snap_ratio_;
|
||||||
|
mapnik::value_double simplify_dp_ratio_;
|
||||||
|
mapnik::value_double simplify_prefilter_;
|
||||||
|
bool simplify_dp_preserve_;
|
||||||
|
mapnik::value_double simplify_clip_resolution_;
|
||||||
boost::regex pattern_;
|
boost::regex pattern_;
|
||||||
int intersect_min_scale_;
|
int intersect_min_scale_;
|
||||||
int intersect_max_scale_;
|
int intersect_max_scale_;
|
||||||
|
|
|
@ -49,14 +49,16 @@ postgis_featureset::postgis_featureset(std::shared_ptr<IResultSet> const& rs,
|
||||||
context_ptr const& ctx,
|
context_ptr const& ctx,
|
||||||
std::string const& encoding,
|
std::string const& encoding,
|
||||||
bool key_field,
|
bool key_field,
|
||||||
bool key_field_as_attribute)
|
bool key_field_as_attribute,
|
||||||
|
bool twkb_encoding)
|
||||||
: rs_(rs),
|
: rs_(rs),
|
||||||
ctx_(ctx),
|
ctx_(ctx),
|
||||||
tr_(new transcoder(encoding)),
|
tr_(new transcoder(encoding)),
|
||||||
totalGeomSize_(0),
|
totalGeomSize_(0),
|
||||||
feature_id_(1),
|
feature_id_(1),
|
||||||
key_field_(key_field),
|
key_field_(key_field),
|
||||||
key_field_as_attribute_(key_field_as_attribute)
|
key_field_as_attribute_(key_field_as_attribute),
|
||||||
|
twkb_encoding_(twkb_encoding)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,8 +125,14 @@ feature_ptr postgis_featureset::next()
|
||||||
int size = rs_->getFieldLength(0);
|
int size = rs_->getFieldLength(0);
|
||||||
const char *data = rs_->getValue(0);
|
const char *data = rs_->getValue(0);
|
||||||
|
|
||||||
mapnik::geometry::geometry<double> geometry = geometry_utils::from_wkb(data, size);
|
if (twkb_encoding_ )
|
||||||
feature->set_geometry(std::move(geometry));
|
{
|
||||||
|
feature->set_geometry(geometry_utils::from_twkb(data, size));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
feature->set_geometry(geometry_utils::from_wkb(data, size));
|
||||||
|
}
|
||||||
|
|
||||||
totalGeomSize_ += size;
|
totalGeomSize_ += size;
|
||||||
unsigned num_attrs = ctx_->size() + 1;
|
unsigned num_attrs = ctx_->size() + 1;
|
||||||
|
|
|
@ -44,7 +44,8 @@ public:
|
||||||
context_ptr const& ctx,
|
context_ptr const& ctx,
|
||||||
std::string const& encoding,
|
std::string const& encoding,
|
||||||
bool key_field,
|
bool key_field,
|
||||||
bool key_field_as_attribute);
|
bool key_field_as_attribute,
|
||||||
|
bool twkb_encoding);
|
||||||
feature_ptr next();
|
feature_ptr next();
|
||||||
~postgis_featureset();
|
~postgis_featureset();
|
||||||
|
|
||||||
|
@ -56,6 +57,7 @@ private:
|
||||||
mapnik::value_integer feature_id_;
|
mapnik::value_integer feature_id_;
|
||||||
bool key_field_;
|
bool key_field_;
|
||||||
bool key_field_as_attribute_;
|
bool key_field_as_attribute_;
|
||||||
|
bool twkb_encoding_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // POSTGIS_FEATURESET_HPP
|
#endif // POSTGIS_FEATURESET_HPP
|
||||||
|
|
Loading…
Add table
Reference in a new issue