forked from osm2pgsql-dev/osm2pgsql
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathoutput-multi.cpp
More file actions
331 lines (295 loc) · 10.8 KB
/
Copy pathoutput-multi.cpp
File metadata and controls
331 lines (295 loc) · 10.8 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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
#include "output-multi.hpp"
#include "expire-tiles.hpp"
#include "id-tracker.hpp"
#include "middle.hpp"
#include "options.hpp"
#include "table.hpp"
#include "taginfo-impl.hpp"
#include "tagtransform.hpp"
#include "wkb.hpp"
#include <boost/algorithm/string/predicate.hpp>
#include <vector>
output_multi_t::output_multi_t(
std::string const &name, std::shared_ptr<geometry_processor> processor_,
export_list const &export_list, std::shared_ptr<middle_query_t> const &mid,
options_t const &options,
std::shared_ptr<db_copy_thread_t> const ©_thread)
: output_t(mid, options),
m_tagtransform(tagtransform_t::make_tagtransform(&m_options, export_list)),
m_processor(processor_), m_proj(m_options.projection),
// TODO: we could in fact have something that is interested in nodes and
// ways..
m_osm_type(m_processor->interests(geometry_processor::interest_node)
? osmium::item_type::node
: osmium::item_type::way),
m_table(new table_t{name, m_processor->column_type(),
export_list.normal_columns(m_osm_type),
m_options.hstore_columns, m_processor->srid(),
m_options.append, m_options.hstore_mode, copy_thread}),
m_expire(m_options.expire_tiles_zoom, m_options.expire_tiles_max_bbox,
m_options.projection),
buffer(1024, osmium::memory::Buffer::auto_grow::yes),
m_builder(m_options.projection),
m_way_area(export_list.has_column(m_osm_type, "way_area"))
{}
output_multi_t::output_multi_t(
output_multi_t const *other, std::shared_ptr<middle_query_t> const &mid,
std::shared_ptr<db_copy_thread_t> const ©_thread)
: output_t(mid, other->m_options),
m_tagtransform(other->m_tagtransform->clone()),
m_processor(other->m_processor), m_proj(other->m_proj),
m_osm_type(other->m_osm_type),
m_table(new table_t{*other->m_table, copy_thread}),
m_expire(m_options.expire_tiles_zoom, m_options.expire_tiles_max_bbox,
m_options.projection),
buffer(1024, osmium::memory::Buffer::auto_grow::yes),
m_builder(m_options.projection), m_way_area(other->m_way_area)
{}
output_multi_t::~output_multi_t() = default;
std::shared_ptr<output_t> output_multi_t::clone(
std::shared_ptr<middle_query_t> const &mid,
std::shared_ptr<db_copy_thread_t> const ©_thread) const
{
return std::shared_ptr<output_t>(
new output_multi_t{this, mid, copy_thread});
}
void output_multi_t::start()
{
m_table->start(m_options.database_options.conninfo(),
m_options.tblsmain_data);
}
void output_multi_t::pending_way(osmid_t id)
{
// Try to fetch the way from the DB
buffer.clear();
if (m_mid->way_get(id, buffer)) {
// Output the way
reprocess_way(&buffer.get<osmium::Way>(0), true);
}
}
void output_multi_t::pending_relation(osmid_t id)
{
// Try to fetch the relation from the DB
buffer.clear();
if (m_mid->relation_get(id, buffer)) {
auto const &rel = buffer.get<osmium::Relation>(0);
process_relation(rel, true);
}
}
void output_multi_t::stop(thread_pool_t *pool)
{
pool->submit([this]() {
m_table->stop(m_options.slim & !m_options.droptemp,
m_options.enable_hstore_index, m_options.tblsmain_index);
});
if (m_options.expire_tiles_zoom_min > 0) {
m_expire.output_and_destroy(m_options.expire_tiles_filename.c_str(),
m_options.expire_tiles_zoom_min);
}
}
void output_multi_t::sync() { m_table->sync(); }
void output_multi_t::node_add(osmium::Node const &node)
{
if (m_processor->interests(geometry_processor::interest_node)) {
process_node(node);
}
}
void output_multi_t::way_add(osmium::Way *way)
{
if (m_processor->interests(geometry_processor::interest_way) &&
way->nodes().size() > 1) {
process_way(way);
}
}
void output_multi_t::relation_add(osmium::Relation const &rel)
{
if (m_processor->interests(geometry_processor::interest_relation) &&
!rel.members().empty()) {
process_relation(rel, false);
}
}
void output_multi_t::node_modify(osmium::Node const &node)
{
if (m_processor->interests(geometry_processor::interest_node)) {
// TODO - need to know it's a node?
delete_from_output(node.id());
// TODO: need to mark any ways or relations using it - depends on what
// type of output this is... delegate to the geometry processor??
process_node(node);
}
}
void output_multi_t::way_modify(osmium::Way *way)
{
if (m_processor->interests(geometry_processor::interest_way)) {
// TODO - need to know it's a way?
delete_from_output(way->id());
// TODO: need to mark any relations using it - depends on what
// type of output this is... delegate to the geometry processor??
process_way(way);
}
}
void output_multi_t::relation_modify(osmium::Relation const &rel)
{
if (m_processor->interests(geometry_processor::interest_relation)) {
// TODO - need to know it's a relation?
delete_from_output(-rel.id());
// TODO: need to mark any other relations using it - depends on what
// type of output this is... delegate to the geometry processor??
process_relation(rel, false);
}
}
void output_multi_t::node_delete(osmid_t id)
{
if (m_processor->interests(geometry_processor::interest_node)) {
// TODO - need to know it's a node?
delete_from_output(id);
}
}
void output_multi_t::way_delete(osmid_t id)
{
if (m_processor->interests(geometry_processor::interest_way)) {
// TODO - need to know it's a way?
delete_from_output(id);
}
}
void output_multi_t::relation_delete(osmid_t id)
{
if (m_processor->interests(geometry_processor::interest_relation)) {
// TODO - need to know it's a relation?
delete_from_output(-id);
}
}
void output_multi_t::process_node(osmium::Node const &node)
{
// check if we are keeping this node
taglist_t outtags;
auto filter =
m_tagtransform->filter_tags(node, nullptr, nullptr, outtags, true);
if (!filter) {
// grab its geom
auto geom = m_processor->process_node(node.location(), &m_builder);
if (!geom.empty()) {
m_expire.from_wkb(geom.c_str(), node.id());
copy_node_to_table(node.id(), geom, outtags);
}
}
}
void output_multi_t::reprocess_way(osmium::Way *way, bool exists)
{
//if the way could exist already we have to make the relation pending and reprocess it later
//but only if we actually care about relations
if (m_processor->interests(geometry_processor::interest_relation) &&
exists) {
way_delete(way->id());
}
//check if we are keeping this way
taglist_t outtags;
auto const filter =
m_tagtransform->filter_tags(*way, nullptr, nullptr, outtags, true);
if (!filter) {
m_mid->nodes_get_list(&(way->nodes()));
auto geom = m_processor->process_way(*way, &m_builder);
if (!geom.empty()) {
copy_to_table(way->id(), geom, outtags);
}
}
}
void output_multi_t::process_way(osmium::Way *way)
{
//check if we are keeping this way
taglist_t outtags;
auto const filter =
m_tagtransform->filter_tags(*way, nullptr, nullptr, outtags, true);
if (!filter) {
//get the geom from the middle
if (m_mid->nodes_get_list(&(way->nodes())) < 1) {
return;
}
//grab its geom
auto const geom = m_processor->process_way(*way, &m_builder);
if (!geom.empty()) {
copy_to_table(way->id(), geom, outtags);
}
}
}
void output_multi_t::process_relation(osmium::Relation const &rel, bool exists)
{
//if it may exist already, delete it first
if (exists) {
relation_delete(rel.id());
}
//does this relation have anything interesting to us
taglist_t rel_outtags;
auto filter =
m_tagtransform->filter_tags(rel, nullptr, nullptr, rel_outtags, true);
if (!filter) {
//TODO: move this into geometry processor, figure a way to come back for tag transform
//grab ways/nodes of the members in the relation, bail if none were used
if (m_relation_helper.set(rel, m_mid.get()) < 1) {
return;
}
//NOTE: make_polygon is preset here this is to force the tag matching
//normally this wouldnt work but we tell the tag transform to allow typeless relations
//this is needed because the type can get stripped off by the rel_tag filter above
//if the export list did not include the type tag.
//TODO: find a less hacky way to do the matching and tag copying stuff without
//all this trickery
int roads;
int make_boundary, make_polygon;
taglist_t outtags;
filter = m_tagtransform->filter_rel_member_tags(
rel_outtags, m_relation_helper.data, m_relation_helper.roles,
&make_boundary, &make_polygon, &roads, outtags, true);
if (!filter) {
m_relation_helper.add_way_locations(m_mid.get());
auto const geoms = m_processor->process_relation(
rel, m_relation_helper.data, &m_builder);
for (auto const &geom : geoms) {
copy_to_table(-rel.id(), geom, outtags);
}
}
}
}
void output_multi_t::copy_node_to_table(osmid_t id, std::string const &geom,
taglist_t &tags)
{
m_table->write_row(id, tags, geom);
}
/**
* Copies a 2d object(line or polygon) to the table, adding a way_area tag if appropriate
* \param id OSM ID of the object
* \param geom Geometry string of the object
* \param tags List of tags. May be modified.
* \param polygon Polygon flag returned from the tag transform (polygon=1)
*
* \pre geom must be valid.
*/
void output_multi_t::copy_to_table(osmid_t const id,
geometry_processor::wkb_t const &geom,
taglist_t &tags)
{
// XXX really should depend on expected output type
if (m_way_area) {
// It's a polygon table (implied by it turning into a poly),
// and it got formed into a polygon, so expire as a polygon and write the geom
auto area =
ewkb::parser_t(geom).get_area<osmium::geom::IdentityProjection>();
util::double_to_buffer tmp{area};
tags.set("way_area", tmp.c_str());
}
m_expire.from_wkb(geom.c_str(), id);
m_table->write_row(id, tags, geom);
}
void output_multi_t::delete_from_output(osmid_t id)
{
if (m_expire.from_db(m_table.get(), id)) {
m_table->delete_row(id);
}
}
void output_multi_t::merge_expire_trees(output_t *other)
{
auto *const omulti = dynamic_cast<output_multi_t *>(other);
if (omulti) {
m_expire.merge_and_destroy(omulti->m_expire);
}
}