-
-
Notifications
You must be signed in to change notification settings - Fork 477
Expand file tree
/
Copy pathlocator.cpp
More file actions
150 lines (130 loc) · 4.79 KB
/
locator.cpp
File metadata and controls
150 lines (130 loc) · 4.79 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/**
* SPDX-License-Identifier: GPL-2.0-or-later
*
* This file is part of osm2pgsql (https://osm2pgsql.org/).
*
* Copyright (C) 2006-2026 by the osm2pgsql developer community.
* For a full list of authors see the git log.
*/
#include "locator.hpp"
#include "geom-boost-adaptor.hpp"
#include "geom-box.hpp"
#include "geom-functions.hpp"
#include "hex.hpp"
#include "overloaded.hpp"
#include "pgsql-capabilities.hpp"
#include "pgsql.hpp"
#include "projection.hpp"
#include "wkb.hpp"
#include <iterator>
void locator_t::add_region(std::string const &name, geom::box_t const &box)
{
m_regions.emplace_back(name, box);
}
void locator_t::add_region(std::string const &name,
geom::geometry_t const &geom)
{
if (geom.is_polygon()) {
m_regions.emplace_back(name, geom.get<geom::polygon_t>());
return;
}
if (geom.is_multipolygon()) {
for (auto const &polygon : geom.get<geom::multipolygon_t>()) {
m_regions.emplace_back(name, polygon);
}
return;
}
throw std::runtime_error{
"Invalid geometry type: Need (multi)polygon for region."};
}
void locator_t::add_regions(pg_conn_t const &db_connection,
std::string const &query)
{
log_debug("Querying database for locator '{}'...", name());
auto const result = db_connection.exec(query);
if (result.num_fields() != 2) {
throw std::runtime_error{"Locator queries must return exactly two "
"columns with the name and the geometry."};
}
if (!is_geometry_type(result.field_type(1))) {
throw std::runtime_error{
"Second column in Locator query results must be a geometry."};
}
for (int n = 0; n < result.num_tuples(); ++n) {
std::string const name = result.get_value(n, 0);
auto geometry = ewkb_to_geom(util::decode_hex(result.get(n, 1)));
if (geometry.srid() == PROJ_LATLONG) {
add_region(name, geometry);
} else {
log_warn("Ignoring locator geometry that is not in WGS84 (4326)");
}
}
log_info("Added {} regions to locator '{}'.", result.num_tuples(), name());
}
void locator_t::build_index()
{
log_debug("Building index for locator '{}'", name());
std::vector<idx_value_t> m_data;
m_data.reserve(m_regions.size());
std::size_t n = 0;
for (auto const ®ion : m_regions) {
m_data.emplace_back(region.box(), n++);
}
m_rtree.clear();
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 ®ion = 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()) {
build_index();
}
std::set<std::string> results;
all_intersecting_visit(geom, &results);
return results;
}
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();
}
}});
}
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;
}