Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge pull request #1499 from manelclos/master

Query tolerance for features_at_point
  • Loading branch information...
commit 86e805b33e63d96dc824140351e42e245ccfcd36 2 parents 8674e46 + 4935660
@springmeyer springmeyer authored
Showing with 93 additions and 50 deletions.
  1. +1 −1  include/mapnik/datasource.hpp
  2. +1 −1  include/mapnik/memory_datasource.hpp
  3. +1 −1  plugins/input/csv/csv_datasource.cpp
  4. +1 −1  plugins/input/csv/csv_datasource.hpp
  5. +1 −1  plugins/input/gdal/gdal_datasource.cpp
  6. +1 −1  plugins/input/gdal/gdal_datasource.hpp
  7. +1 −1  plugins/input/geojson/geojson_datasource.cpp
  8. +1 −1  plugins/input/geojson/geojson_datasource.hpp
  9. +1 −1  plugins/input/geos/geos_datasource.cpp
  10. +1 −1  plugins/input/geos/geos_datasource.hpp
  11. +1 −1  plugins/input/kismet/kismet_datasource.cpp
  12. +1 −1  plugins/input/kismet/kismet_datasource.hpp
  13. +1 −1  plugins/input/occi/occi_datasource.cpp
  14. +1 −1  plugins/input/occi/occi_datasource.hpp
  15. +1 −1  plugins/input/ogr/ogr_datasource.cpp
  16. +1 −1  plugins/input/ogr/ogr_datasource.hpp
  17. +1 −1  plugins/input/osm/osm_datasource.cpp
  18. +1 −1  plugins/input/osm/osm_datasource.hpp
  19. +2 −2 plugins/input/postgis/postgis_datasource.cpp
  20. +1 −1  plugins/input/postgis/postgis_datasource.hpp
  21. +1 −1  plugins/input/python/python_datasource.cpp
  22. +1 −1  plugins/input/python/python_datasource.hpp
  23. +1 −1  plugins/input/raster/raster_datasource.cpp
  24. +1 −1  plugins/input/raster/raster_datasource.hpp
  25. +1 −1  plugins/input/rasterlite/rasterlite_datasource.cpp
  26. +1 −1  plugins/input/rasterlite/rasterlite_datasource.hpp
  27. +1 −1  plugins/input/shape/shape_datasource.cpp
  28. +1 −1  plugins/input/shape/shape_datasource.hpp
  29. +1 −1  plugins/input/sqlite/sqlite_datasource.cpp
  30. +1 −1  plugins/input/sqlite/sqlite_datasource.hpp
  31. +1 −1  plugins/input/templates/helloworld/hello_datasource.cpp
  32. +1 −1  plugins/input/templates/helloworld/hello_datasource.hpp
  33. +16 −16 src/map.cpp
  34. +1 −1  src/memory_datasource.cpp
  35. +43 −0 tests/python_tests/query_tolerance_test.py
View
2  include/mapnik/datasource.hpp
@@ -115,7 +115,7 @@ class MAPNIK_DECL datasource : private boost::noncopyable
virtual void bind() const {}
virtual featureset_ptr features(query const& q) const = 0;
- virtual featureset_ptr features_at_point(coord2d const& pt) const = 0;
+ virtual featureset_ptr features_at_point(coord2d const& pt, double tol = 0) 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;
View
2  include/mapnik/memory_datasource.hpp
@@ -41,7 +41,7 @@ class MAPNIK_DECL memory_datasource : public datasource
void push(feature_ptr feature);
datasource::datasource_t type() const;
featureset_ptr features(const query& q) const;
- featureset_ptr features_at_point(coord2d const& pt) const;
+ featureset_ptr features_at_point(coord2d const& pt, double tol = 0) const;
box2d<double> envelope() const;
boost::optional<geometry_t> get_geometry_type() const;
layer_descriptor get_descriptor() const;
View
2  plugins/input/csv/csv_datasource.cpp
@@ -959,7 +959,7 @@ mapnik::featureset_ptr csv_datasource::features(mapnik::query const& q) const
return boost::make_shared<mapnik::memory_featureset>(q.get_bbox(),features_);
}
-mapnik::featureset_ptr csv_datasource::features_at_point(mapnik::coord2d const& pt) const
+mapnik::featureset_ptr csv_datasource::features_at_point(mapnik::coord2d const& pt, double tol) const
{
if (!is_bound_) bind();
View
2  plugins/input/csv/csv_datasource.hpp
@@ -47,7 +47,7 @@ class csv_datasource : public mapnik::datasource
mapnik::datasource::datasource_t type() const;
static const char * name();
mapnik::featureset_ptr features(mapnik::query const& q) const;
- mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const;
+ mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt, double tol = 0) const;
mapnik::box2d<double> envelope() const;
boost::optional<mapnik::datasource::geometry_t> get_geometry_type() const;
mapnik::layer_descriptor get_descriptor() const;
View
2  plugins/input/gdal/gdal_datasource.cpp
@@ -246,7 +246,7 @@ featureset_ptr gdal_datasource::features(query const& q) const
nodata_value_));
}
-featureset_ptr gdal_datasource::features_at_point(coord2d const& pt) const
+featureset_ptr gdal_datasource::features_at_point(coord2d const& pt, double tol) const
{
if (! is_bound_) bind();
View
2  plugins/input/gdal/gdal_datasource.hpp
@@ -50,7 +50,7 @@ class gdal_datasource : public mapnik::datasource
mapnik::datasource::datasource_t type() const;
static const char * name();
mapnik::featureset_ptr features(mapnik::query const& q) const;
- mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const;
+ mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt, double tol = 0) const;
mapnik::box2d<double> envelope() const;
boost::optional<mapnik::datasource::geometry_t> get_geometry_type() const;
mapnik::layer_descriptor get_descriptor() const;
View
2  plugins/input/geojson/geojson_datasource.cpp
@@ -217,7 +217,7 @@ mapnik::featureset_ptr geojson_datasource::features(mapnik::query const& q) cons
}
// FIXME
-mapnik::featureset_ptr geojson_datasource::features_at_point(mapnik::coord2d const& pt) const
+mapnik::featureset_ptr geojson_datasource::features_at_point(mapnik::coord2d const& pt, double tol) const
{
if (!is_bound_) bind();
throw mapnik::datasource_exception("GeoJSON Plugin: features_at_point is not supported yet");
View
2  plugins/input/geojson/geojson_datasource.hpp
@@ -60,7 +60,7 @@ class geojson_datasource : public mapnik::datasource
mapnik::datasource::datasource_t type() const;
static const char * name();
mapnik::featureset_ptr features(mapnik::query const& q) const;
- mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const;
+ mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt, double tol = 0) const;
mapnik::box2d<double> envelope() const;
mapnik::layer_descriptor get_descriptor() const;
boost::optional<mapnik::datasource::geometry_t> get_geometry_type() const;
View
2  plugins/input/geos/geos_datasource.cpp
@@ -315,7 +315,7 @@ featureset_ptr geos_datasource::features(query const& q) const
desc_.get_encoding());
}
-featureset_ptr geos_datasource::features_at_point(coord2d const& pt) const
+featureset_ptr geos_datasource::features_at_point(coord2d const& pt, double tol) const
{
if (! is_bound_) bind();
View
2  plugins/input/geos/geos_datasource.hpp
@@ -50,7 +50,7 @@ class geos_datasource : public mapnik::datasource
mapnik::datasource::datasource_t type() const;
static const char * name();
mapnik::featureset_ptr features(mapnik::query const& q) const;
- mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const;
+ mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt, double tol = 0) const;
mapnik::box2d<double> envelope() const;
boost::optional<mapnik::datasource::geometry_t> get_geometry_type() const;
mapnik::layer_descriptor get_descriptor() const;
View
2  plugins/input/kismet/kismet_datasource.cpp
@@ -166,7 +166,7 @@ featureset_ptr kismet_datasource::features(query const& q) const
// return featureset_ptr();
}
-featureset_ptr kismet_datasource::features_at_point(coord2d const& pt) const
+featureset_ptr kismet_datasource::features_at_point(coord2d const& pt, double tol) const
{
if (! is_bound_) bind();
View
2  plugins/input/kismet/kismet_datasource.hpp
@@ -52,7 +52,7 @@ class kismet_datasource : public mapnik::datasource
datasource::datasource_t type() const;
static const char * name();
mapnik::featureset_ptr features(mapnik::query const& q) const;
- mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const;
+ mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt, double tol = 0) const;
mapnik::box2d<double> envelope() const;
boost::optional<mapnik::datasource::geometry_t> get_geometry_type() const;
mapnik::layer_descriptor get_descriptor() const;
View
2  plugins/input/occi/occi_datasource.cpp
@@ -590,7 +590,7 @@ featureset_ptr occi_datasource::features(query const& q) const
row_prefetch_);
}
-featureset_ptr occi_datasource::features_at_point(coord2d const& pt) const
+featureset_ptr occi_datasource::features_at_point(coord2d const& pt, double tol) const
{
if (! is_bound_) bind();
View
2  plugins/input/occi/occi_datasource.hpp
@@ -51,7 +51,7 @@ class occi_datasource : public mapnik::datasource
mapnik::datasource::datasource_t type() const;
static const char * name();
mapnik::featureset_ptr features(mapnik::query const& q) const;
- mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const;
+ mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt, double tol = 0) const;
mapnik::box2d<double> envelope() const;
boost::optional<mapnik::datasource::geometry_t> get_geometry_type() const;
mapnik::layer_descriptor get_descriptor() const;
View
2  plugins/input/ogr/ogr_datasource.cpp
@@ -519,7 +519,7 @@ featureset_ptr ogr_datasource::features(query const& q) const
return featureset_ptr();
}
-featureset_ptr ogr_datasource::features_at_point(coord2d const& pt) const
+featureset_ptr ogr_datasource::features_at_point(coord2d const& pt, double tol) const
{
if (!is_bound_) bind();
View
2  plugins/input/ogr/ogr_datasource.hpp
@@ -52,7 +52,7 @@ class ogr_datasource : public mapnik::datasource
mapnik::datasource::datasource_t type() const;
static const char * name();
mapnik::featureset_ptr features(mapnik::query const& q) const;
- mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const;
+ mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt, double tol = 0) const;
mapnik::box2d<double> envelope() const;
boost::optional<mapnik::datasource::geometry_t> get_geometry_type() const;
mapnik::layer_descriptor get_descriptor() const;
View
2  plugins/input/osm/osm_datasource.cpp
@@ -158,7 +158,7 @@ featureset_ptr osm_datasource::features(const query& q) const
desc_.get_encoding());
}
-featureset_ptr osm_datasource::features_at_point(coord2d const& pt) const
+featureset_ptr osm_datasource::features_at_point(coord2d const& pt, double tol) const
{
if (!is_bound_) bind();
View
2  plugins/input/osm/osm_datasource.hpp
@@ -58,7 +58,7 @@ class osm_datasource : public datasource
mapnik::datasource::datasource_t type() const;
static const char * name();
featureset_ptr features(const query& q) const;
- featureset_ptr features_at_point(coord2d const& pt) const;
+ featureset_ptr features_at_point(coord2d const& pt, double tol = 0) const;
box2d<double> envelope() const;
boost::optional<mapnik::datasource::geometry_t> get_geometry_type() const;
layer_descriptor get_descriptor() const;
View
4 plugins/input/postgis/postgis_datasource.cpp
@@ -709,7 +709,7 @@ featureset_ptr postgis_datasource::features(const query& q) const
return featureset_ptr();
}
-featureset_ptr postgis_datasource::features_at_point(coord2d const& pt) const
+featureset_ptr postgis_datasource::features_at_point(coord2d const& pt, double tol) const
{
if (! is_bound_)
{
@@ -778,7 +778,7 @@ featureset_ptr postgis_datasource::features_at_point(coord2d const& pt) const
}
}
- box2d<double> box(pt.x, pt.y, pt.x, pt.y);
+ box2d<double> box(pt.x - tol, pt.y - tol, pt.x + tol, pt.y + tol);
std::string table_with_bbox = populate_tokens(table_, FMAX, box, 0, 0);
s << " FROM " << table_with_bbox;
View
2  plugins/input/postgis/postgis_datasource.hpp
@@ -63,7 +63,7 @@ class postgis_datasource : public datasource
mapnik::datasource::datasource_t type() const;
static const char * name();
featureset_ptr features(const query& q) const;
- featureset_ptr features_at_point(coord2d const& pt) const;
+ featureset_ptr features_at_point(coord2d const& pt, double tol = 0) const;
mapnik::box2d<double> envelope() const;
boost::optional<mapnik::datasource::geometry_t> get_geometry_type() const;
layer_descriptor get_descriptor() const;
View
2  plugins/input/python/python_datasource.cpp
@@ -189,7 +189,7 @@ mapnik::featureset_ptr python_datasource::features(mapnik::query const& q) const
return mapnik::featureset_ptr();
}
-mapnik::featureset_ptr python_datasource::features_at_point(mapnik::coord2d const& pt) const
+mapnik::featureset_ptr python_datasource::features_at_point(mapnik::coord2d const& pt, double tol) const
{
using namespace boost::python;
View
2  plugins/input/python/python_datasource.hpp
@@ -29,7 +29,7 @@ class python_datasource : public mapnik::datasource
// mandatory: function to query features by point (coord2d)
// not used by rendering, but available to calling applications
- mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const;
+ mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt, double tol = 0) const;
// mandatory: return the box2d of the datasource
// called during rendering to determine if the layer should be processed
View
2  plugins/input/raster/raster_datasource.cpp
@@ -220,7 +220,7 @@ featureset_ptr raster_datasource::features(query const& q) const
}
}
-featureset_ptr raster_datasource::features_at_point(coord2d const&) const
+featureset_ptr raster_datasource::features_at_point(coord2d const&, double tol) const
{
MAPNIK_LOG_WARN(raster) << "raster_datasource: feature_at_point not supported";
View
2  plugins/input/raster/raster_datasource.hpp
@@ -49,7 +49,7 @@ class raster_datasource : public mapnik::datasource
datasource::datasource_t type() const;
static const char * name();
mapnik::featureset_ptr features(const mapnik::query& q) const;
- mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const;
+ mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt, double tol = 0) const;
mapnik::box2d<double> envelope() const;
boost::optional<mapnik::datasource::geometry_t> get_geometry_type() const;
mapnik::layer_descriptor get_descriptor() const;
View
2  plugins/input/rasterlite/rasterlite_datasource.cpp
@@ -201,7 +201,7 @@ featureset_ptr rasterlite_datasource::features(query const& q) const
return boost::make_shared<rasterlite_featureset>(open_dataset(), gq);
}
-featureset_ptr rasterlite_datasource::features_at_point(coord2d const& pt) const
+featureset_ptr rasterlite_datasource::features_at_point(coord2d const& pt, double tol) const
{
if (!is_bound_) bind();
View
2  plugins/input/rasterlite/rasterlite_datasource.hpp
@@ -50,7 +50,7 @@ class rasterlite_datasource : public mapnik::datasource
mapnik::datasource::datasource_t type() const;
static const char * name();
mapnik::featureset_ptr features(mapnik::query const& q) const;
- mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const;
+ mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt, double tol = 0) const;
mapnik::box2d<double> envelope() const;
boost::optional<mapnik::datasource::geometry_t> get_geometry_type() const;
mapnik::layer_descriptor get_descriptor() const;
View
2  plugins/input/shape/shape_datasource.cpp
@@ -286,7 +286,7 @@ featureset_ptr shape_datasource::features(const query& q) const
}
}
-featureset_ptr shape_datasource::features_at_point(coord2d const& pt) const
+featureset_ptr shape_datasource::features_at_point(coord2d const& pt, double tol) const
{
if (!is_bound_) bind();
View
2  plugins/input/shape/shape_datasource.hpp
@@ -57,7 +57,7 @@ class shape_datasource : public datasource
datasource::datasource_t type() const;
static const char * name();
featureset_ptr features(const query& q) const;
- featureset_ptr features_at_point(coord2d const& pt) const;
+ featureset_ptr features_at_point(coord2d const& pt, double tol = 0) const;
box2d<double> envelope() const;
boost::optional<mapnik::datasource::geometry_t> get_geometry_type() const;
layer_descriptor get_descriptor() const;
View
2  plugins/input/sqlite/sqlite_datasource.cpp
@@ -632,7 +632,7 @@ featureset_ptr sqlite_datasource::features(query const& q) const
return featureset_ptr();
}
-featureset_ptr sqlite_datasource::features_at_point(coord2d const& pt) const
+featureset_ptr sqlite_datasource::features_at_point(coord2d const& pt, double tol) const
{
if (! is_bound_) bind();
View
2  plugins/input/sqlite/sqlite_datasource.hpp
@@ -53,7 +53,7 @@ class sqlite_datasource : public mapnik::datasource
datasource::datasource_t type() const;
static const char * name();
mapnik::featureset_ptr features(mapnik::query const& q) const;
- mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const;
+ mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt, double tol = 0) const;
mapnik::box2d<double> envelope() const;
boost::optional<mapnik::datasource::geometry_t> get_geometry_type() const;
mapnik::layer_descriptor get_descriptor() const;
View
2  plugins/input/templates/helloworld/hello_datasource.cpp
@@ -82,7 +82,7 @@ mapnik::featureset_ptr hello_datasource::features(mapnik::query const& q) const
return mapnik::featureset_ptr();
}
-mapnik::featureset_ptr hello_datasource::features_at_point(mapnik::coord2d const& pt) const
+mapnik::featureset_ptr hello_datasource::features_at_point(mapnik::coord2d const& pt, double tol) const
{
if (!is_bound_) bind();
View
2  plugins/input/templates/helloworld/hello_datasource.hpp
@@ -39,7 +39,7 @@ class hello_datasource : public mapnik::datasource
// mandatory: function to query features by point (coord2d)
// not used by rendering, but available to calling applications
- mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const;
+ mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt, double tol = 0) const;
// mandatory: return the box2d of the datasource
// called during rendering to determine if the layer should be processed
View
32 src/map.cpp
@@ -548,24 +548,24 @@ featureset_ptr Map::query_point(unsigned index, double x, double y) const
{
throw std::runtime_error("query_point: could not project x,y into layer srs");
}
- // TODO - pass tolerance to features_at_point as well
- featureset_ptr fs = ds->features_at_point(mapnik::coord2d(x,y));
+ // calculate default tolerance
+ mapnik::box2d<double> map_ex = current_extent_;
+ if (maximum_extent_)
+ {
+ map_ex.clip(*maximum_extent_);
+ }
+ if (!prj_trans.backward(map_ex,PROJ_ENVELOPE_POINTS))
+ {
+ std::ostringstream s;
+ s << "query_point: could not project map extent '" << map_ex
+ << "' into layer srs for tolerance calculation";
+ throw std::runtime_error(s.str());
+ }
+ double tol = (map_ex.maxx() - map_ex.minx()) / width_ * 3;
+ featureset_ptr fs = ds->features_at_point(mapnik::coord2d(x,y), tol);
+ MAPNIK_LOG_DEBUG(map) << "map: Query at point tol=" << tol << "(" << x << "," << y << ")";
if (fs)
{
- mapnik::box2d<double> map_ex = current_extent_;
- if (maximum_extent_)
- {
- map_ex.clip(*maximum_extent_);
- }
- if (!prj_trans.backward(map_ex,PROJ_ENVELOPE_POINTS))
- {
- std::ostringstream s;
- s << "query_point: could not project map extent '" << map_ex
- << "' into layer srs for tolerance calculation";
- throw std::runtime_error(s.str());
- }
- double tol = (map_ex.maxx() - map_ex.minx()) / width_ * 3;
- MAPNIK_LOG_DEBUG(map) << "map: Query at point tol=" << tol << "(" << x << "," << y << ")";
return boost::make_shared<filter_featureset<hit_test_filter> >(fs,
hit_test_filter(x,y,tol));
}
View
2  src/memory_datasource.cpp
@@ -86,7 +86,7 @@ featureset_ptr memory_datasource::features(const query& q) const
}
-featureset_ptr memory_datasource::features_at_point(coord2d const& pt) const
+featureset_ptr memory_datasource::features_at_point(coord2d const& pt, double tol) const
{
box2d<double> box = box2d<double>(pt.x, pt.y, pt.x, pt.y);
View
43 tests/python_tests/query_tolerance_test.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+
+from nose.tools import *
+from utilities import execution_path
+
+import os, mapnik
+
+def setup():
+ # All of the paths used are relative, if we run the tests
+ # from another directory we need to chdir()
+ os.chdir(execution_path('.'))
+
+def test_query_tolerance():
+ srs = '+init=epsg:4326'
+ lyr = mapnik.Layer('test')
+ lyr.datasource = mapnik.Shapefile(file='../data/shp/arrows.shp')
+ lyr.srs = srs
+ _width = 256
+ _map = mapnik.Map(_width,_width, srs)
+ _map.layers.append(lyr)
+
+ # zoom determines tolerance
+ _map.zoom_all()
+ _map_env = _map.envelope()
+ tol = (_map_env.maxx - _map_env.minx) / _width * 3
+ # 0.046875 for arrows.shp and zoom_all
+ assert tol == 0.046875
+
+ # check point really exists
+ x, y = 2.0, 4.0
+ features = _map.query_point(0,x,y).features
+ assert len(features) == 1
+
+ # check inside tolerance limit
+ x = 2.0 + tol * 0.9
+ features = _map.query_point(0,x,y).features
+ assert len(features) == 1
+
+ # check outside tolerance limit
+ x = 2.0 + tol * 1.1
+ features = _map.query_point(0,x,y).features
+ assert len(features) == 0
+
Please sign in to comment.
Something went wrong with that request. Please try again.