artemp 2016-03-14 12:12:54 +01:00
parent 2204a983c6
commit 7d4f894d98
4 changed files with 122 additions and 20 deletions

View file

@ -88,6 +88,17 @@ postgis_datasource::postgis_datasource(parameters const& params)
extent_from_subquery_(*params.get<mapnik::boolean_type>("extent_from_subquery", false)),
max_async_connections_(*params_.get<mapnik::value_integer>("max_async_connection", 1)),
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+!)"
pattern_(boost::regex("(@\\w+)",boost::regex::normal | boost::regbase::icase)),
// 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);
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_);
CnxPool_ptr pool = ConnectionManager::instance().getPool(creator_.id());
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_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_) {
s << "ST_Simplify(";
// What number of decimals of rounding does the pixel size imply?
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_) {
// 1/20 of pixel seems to be a good compromise to avoid
// drop of collapsed polygons.
// See https://github.com/mapnik/mapnik/issues/1639
const double tolerance = std::min(px_gw, px_gh) / 20.0;
s << ", " << tolerance << ")";
// ! ST_SnapToGrid()
if (simplify_geometries_ && simplify_snap_ratio_ > 0.0)
{
const double tolerance = px_sz * simplify_snap_ratio_;
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>();
std::set<std::string> const& props = q.property_names();
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);
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);
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_);
}
}

View file

@ -119,6 +119,13 @@ private:
bool estimate_extent_;
int max_async_connections_;
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_;
int intersect_min_scale_;
int intersect_max_scale_;

View file

@ -49,14 +49,16 @@ postgis_featureset::postgis_featureset(std::shared_ptr<IResultSet> const& rs,
context_ptr const& ctx,
std::string const& encoding,
bool key_field,
bool key_field_as_attribute)
bool key_field_as_attribute,
bool twkb_encoding)
: rs_(rs),
ctx_(ctx),
tr_(new transcoder(encoding)),
totalGeomSize_(0),
feature_id_(1),
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);
const char *data = rs_->getValue(0);
mapnik::geometry::geometry<double> geometry = geometry_utils::from_wkb(data, size);
feature->set_geometry(std::move(geometry));
if (twkb_encoding_ )
{
feature->set_geometry(geometry_utils::from_twkb(data, size));
}
else
{
feature->set_geometry(geometry_utils::from_wkb(data, size));
}
totalGeomSize_ += size;
unsigned num_attrs = ctx_->size() + 1;

View file

@ -44,7 +44,8 @@ public:
context_ptr const& ctx,
std::string const& encoding,
bool key_field,
bool key_field_as_attribute);
bool key_field_as_attribute,
bool twkb_encoding);
feature_ptr next();
~postgis_featureset();
@ -56,6 +57,7 @@ private:
mapnik::value_integer feature_id_;
bool key_field_;
bool key_field_as_attribute_;
bool twkb_encoding_;
};
#endif // POSTGIS_FEATURESET_HPP