diff --git a/src/locator.cpp b/src/locator.cpp index 73e49ef87..35fcbd584 100644 --- a/src/locator.cpp +++ b/src/locator.cpp @@ -88,44 +88,63 @@ void locator_t::build_index() m_rtree.insert(m_data.cbegin(), m_data.cend()); } -std::set locator_t::all_intersecting(geom::geometry_t const &geom) +void locator_t::all_intersecting_visit(geom::geometry_t const &geom, + std::set *results) { - if (m_rtree.size() < m_regions.size()) { - build_index(); - } - - std::set results; - - geom.visit(overloaded{[&](geom::nullgeom_t const & /*input*/) {}, - [&](geom::collection_t const & /*input*/) {}, // TODO + geom.visit(overloaded{[&](geom::nullgeom_t const & /*val*/) {}, + [&](geom::collection_t const &val) { + for (auto const &sgeom : val) { + all_intersecting_visit(sgeom, results); + } + }, [&](auto const &val) { for (auto it = begin_intersects(val); it != end_query(); ++it) { auto const ®ion = m_regions[it->second]; - results.emplace(region.name()); + results->emplace(region.name()); } }}); - - return results; } -std::string locator_t::first_intersecting(geom::geometry_t const &geom) +std::set locator_t::all_intersecting(geom::geometry_t const &geom) { if (m_rtree.size() < m_regions.size()) { build_index(); } - std::string result; + std::set results; + all_intersecting_visit(geom, &results); + return results; +} - geom.visit(overloaded{[&](geom::nullgeom_t const & /*input*/) {}, - [&](geom::collection_t const & /*input*/) {}, // TODO +void locator_t::first_intersecting_visit(geom::geometry_t const &geom, + std::string *result) +{ + geom.visit(overloaded{[&](geom::nullgeom_t const & /*val*/) {}, + [&](geom::collection_t const &val) { + for (auto const &sgeom : val) { + first_intersecting_visit(sgeom, result); + if (!result->empty()) { + return; + } + } + }, [&](auto const &val) { auto const it = begin_intersects(val); if (it != end_query()) { auto const ®ion = m_regions[it->second]; - result = region.name(); + *result = region.name(); } }}); +} +std::string locator_t::first_intersecting(geom::geometry_t const &geom) +{ + if (m_rtree.size() < m_regions.size()) { + build_index(); + } + + std::string result; + first_intersecting_visit(geom, &result); return result; } diff --git a/src/locator.hpp b/src/locator.hpp index b8d6e44a1..5fdc17b35 100644 --- a/src/locator.hpp +++ b/src/locator.hpp @@ -98,6 +98,12 @@ class locator_t tree_t::const_query_iterator end_query() { return m_rtree.qend(); } + void all_intersecting_visit(geom::geometry_t const &geom, + std::set *results); + + void first_intersecting_visit(geom::geometry_t const &geom, + std::string *result); + public: /// The name of this locator (for logging only) std::string const &name() const noexcept { return m_name; } diff --git a/tests/bdd/flex/locator.feature b/tests/bdd/flex/locator.feature index e4343a241..7a97b6b8f 100644 --- a/tests/bdd/flex/locator.feature +++ b/tests/bdd/flex/locator.feature @@ -80,7 +80,7 @@ Feature: Locators Error in 'first_intersecting': Need locator and geometry arguments """ - Scenario: Use a all_intersecting() without geometry fails + Scenario: Use of all_intersecting() without geometry fails Given the OSM data """ n10 v1 dV Tamenity=post_box x0.5 y0.5 @@ -231,3 +231,69 @@ Feature: Locators | node_id | region | ST_AsText(geom) | | 10 | P1 | 15 8 | + Scenario: Define and use a locator with relation from db + Given the 10.0 grid with origin 10.0 10.0 + | 10 | 11 | 12 | + | 13 | 14 | 15 | + And the OSM data + """ + w29 v1 dV Tregion=P1 Nn10,n11,n14,n13,n10 + """ + And the lua style + """ + local regions = osm2pgsql.define_way_table('osm2pgsql_test_regions', { + { column = 'region', type = 'text' }, + { column = 'geom', type = 'polygon', projection = 4326 }, + }) + + function osm2pgsql.process_way(object) + regions:insert({ + region = object.tags.region, + geom = object:as_polygon(), + }) + end + """ + When running osm2pgsql flex + Then table osm2pgsql_test_regions contains exactly + | way_id | region | ST_AsText(geom) | + | 29 | P1 | (10 0,20 0,20 10,10 10, 10 0) | + + Given the 10.0 grid with origin 10.0 10.0 + | 10 | 11 | 12 | + | 13 | 14 | 15 | + And the OSM data + """ + w20 v1 dV Nn10,n11,n13 + w21 v1 dV Nn13,n10 + w22 v1 dV Nn14,n15 + w23 v1 dV Nn12,n15 + r30 v1 dV Tfoo=bar Mw20@,w21@,w22@,n12@ + r31 v1 dV Tfoo=bar Mn12@,n15@ + r32 v1 dV Tfoo=bar Mw23@ + """ + And the lua style + """ + local regions = osm2pgsql.define_locator({ name = 'regions' }) + regions:add_from_db('SELECT region, geom FROM osm2pgsql_test_regions') + + local points = osm2pgsql.define_relation_table('osm2pgsql_test_rels', { + { column = 'region', type = 'text' }, + { column = 'geom', type = 'geometry', projection = 4326 }, + }) + + function osm2pgsql.process_relation(object) + local g = object:as_geometrycollection() + local r = regions:first_intersecting(g) + if r then + points:insert({ + region = r, + geom = g, + }) + end + end + """ + When running osm2pgsql flex + Then table osm2pgsql_test_rels contains exactly + | relation_id | region | ST_GeometryType(geom) | + | 30 | P1 | ST_GeometryCollection | +