Make locator also work with geometry collections

This commit is contained in:
Jochen Topf
2025-07-03 11:51:17 +02:00
parent 35c6d735e5
commit fe3d7bb002
3 changed files with 110 additions and 19 deletions

View File

@ -88,6 +88,24 @@ void locator_t::build_index()
m_rtree.insert(m_data.cbegin(), m_data.cend());
}
void locator_t::all_intersecting_visit(geom::geometry_t const &geom,
std::set<std::string> *results)
{
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 &region = m_regions[it->second];
results->emplace(region.name());
}
}});
}
std::set<std::string> locator_t::all_intersecting(geom::geometry_t const &geom)
{
if (m_rtree.size() < m_regions.size()) {
@ -95,18 +113,29 @@ std::set<std::string> locator_t::all_intersecting(geom::geometry_t const &geom)
}
std::set<std::string> 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) {
for (auto it = begin_intersects(val);
it != end_query(); ++it) {
auto const it = begin_intersects(val);
if (it != end_query()) {
auto const &region = m_regions[it->second];
results.emplace(region.name());
*result = region.name();
}
}});
return results;
}
std::string locator_t::first_intersecting(geom::geometry_t const &geom)
@ -116,16 +145,6 @@ std::string locator_t::first_intersecting(geom::geometry_t const &geom)
}
std::string result;
geom.visit(overloaded{[&](geom::nullgeom_t const & /*input*/) {},
[&](geom::collection_t const & /*input*/) {}, // TODO
[&](auto const &val) {
auto const it = begin_intersects(val);
if (it != end_query()) {
auto const &region = m_regions[it->second];
result = region.name();
}
}});
first_intersecting_visit(geom, &result);
return result;
}

View File

@ -98,6 +98,12 @@ private:
tree_t::const_query_iterator end_query() { return m_rtree.qend(); }
void all_intersecting_visit(geom::geometry_t const &geom,
std::set<std::string> *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; }

View File

@ -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 |