Libosmium  2.13.0
Fast and flexible C++ library for working with OpenStreetMap data
assembler_legacy.hpp
Go to the documentation of this file.
1 #ifndef OSMIUM_AREA_ASSEMBLER_LEGACY_HPP
2 #define OSMIUM_AREA_ASSEMBLER_LEGACY_HPP
3 
4 /*
5 
6 This file is part of Osmium (http://osmcode.org/libosmium).
7 
8 Copyright 2013-2017 Jochen Topf <jochen@topf.org> and others (see README).
9 
10 Boost Software License - Version 1.0 - August 17th, 2003
11 
12 Permission is hereby granted, free of charge, to any person or organization
13 obtaining a copy of the software and accompanying documentation covered by
14 this license (the "Software") to use, reproduce, display, distribute,
15 execute, and transmit the Software, and to prepare derivative works of the
16 Software, and to permit third-parties to whom the Software is furnished to
17 do so, all subject to the following:
18 
19 The copyright notices in the Software and this entire statement, including
20 the above license grant, this restriction and the following disclaimer,
21 must be included in all copies of the Software, in whole or in part, and
22 all derivative works of the Software, unless such copies or derivative
23 works are solely in the form of machine-executable object code generated by
24 a source language processor.
25 
26 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
29 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
30 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
31 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
32 DEALINGS IN THE SOFTWARE.
33 
34 */
35 
36 #include <algorithm>
37 #include <cassert>
38 #include <cstring>
39 #include <functional>
40 #include <iostream>
41 #include <iterator>
42 #include <set>
43 #include <string>
44 #include <map>
45 #include <utility>
46 #include <vector>
47 
49 #include <osmium/area/detail/basic_assembler_with_tags.hpp>
50 #include <osmium/area/detail/proto_ring.hpp>
51 #include <osmium/area/detail/segment_list.hpp>
53 #include <osmium/area/stats.hpp>
55 #include <osmium/memory/buffer.hpp>
57 #include <osmium/osm/area.hpp>
58 #include <osmium/osm/item_type.hpp>
59 #include <osmium/osm/node_ref.hpp>
60 #include <osmium/osm/relation.hpp>
61 #include <osmium/osm/tag.hpp>
62 #include <osmium/osm/way.hpp>
63 #include <osmium/tags/filter.hpp>
64 
65 namespace osmium {
66 
67  namespace area {
68 
73  class AssemblerLegacy : public detail::BasicAssemblerWithTags {
74 
75  void add_tags_to_area(osmium::builder::AreaBuilder& builder, const osmium::Way& way) const {
76  builder.add_item(way.tags());
77  }
78 
79  void add_common_tags(osmium::builder::TagListBuilder& tl_builder, std::set<const osmium::Way*>& ways) const {
80  std::map<std::string, std::size_t> counter;
81  for (const osmium::Way* way : ways) {
82  for (const auto& tag : way->tags()) {
83  std::string kv{tag.key()};
84  kv.append(1, '\0');
85  kv.append(tag.value());
86  ++counter[kv];
87  }
88  }
89 
90  const std::size_t num_ways = ways.size();
91  for (const auto& t_c : counter) {
92  if (debug()) {
93  std::cerr << " tag " << t_c.first << " is used " << t_c.second << " times in " << num_ways << " ways\n";
94  }
95  if (t_c.second == num_ways) {
96  const std::size_t len = std::strlen(t_c.first.c_str());
97  tl_builder.add_tag(t_c.first.c_str(), t_c.first.c_str() + len + 1);
98  }
99  }
100  }
101 
103 
104  MPFilter() : osmium::tags::KeyFilter(true) {
105  add(false, "type");
106  add(false, "created_by");
107  add(false, "source");
108  add(false, "note");
109  add(false, "test:id");
110  add(false, "test:section");
111  }
112 
113  }; // struct MPFilter
114 
115  static const MPFilter& filter() noexcept {
116  static const MPFilter filter;
117  return filter;
118  }
119 
121  const auto count = std::count_if(relation.tags().cbegin(), relation.tags().cend(), std::cref(filter()));
122 
123  if (debug()) {
124  std::cerr << " found " << count << " tags on relation (without ignored ones)\n";
125  }
126 
127  if (count > 0) {
128  if (debug()) {
129  std::cerr << " use tags from relation\n";
130  }
131 
132  if (config().keep_type_tag) {
133  builder.add_item(relation.tags());
134  } else {
135  copy_tags_without_type(builder, relation.tags());
136  }
137  } else {
138  ++stats().no_tags_on_relation;
139  if (debug()) {
140  std::cerr << " use tags from outer ways\n";
141  }
142  std::set<const osmium::Way*> ways;
143  for (const auto& ring : rings()) {
144  if (ring.is_outer()) {
145  ring.get_ways(ways);
146  }
147  }
148  if (ways.size() == 1) {
149  if (debug()) {
150  std::cerr << " only one outer way\n";
151  }
152  builder.add_item((*ways.cbegin())->tags());
153  } else {
154  if (debug()) {
155  std::cerr << " multiple outer ways, get common tags\n";
156  }
157  osmium::builder::TagListBuilder tl_builder{builder};
158  add_common_tags(tl_builder, ways);
159  }
160  }
161  }
162 
163  bool create_area(osmium::memory::Buffer& out_buffer, const osmium::Way& way) {
164  osmium::builder::AreaBuilder builder{out_buffer};
165  builder.initialize_from_object(way);
166 
167  const bool area_okay = create_rings();
168  if (area_okay || config().create_empty_areas) {
169  add_tags_to_area(builder, way);
170  }
171  if (area_okay) {
172  add_rings_to_area(builder);
173  }
174 
175  if (report_ways()) {
176  config().problem_reporter->report_way(way);
177  }
178 
179  return area_okay || config().create_empty_areas;
180  }
181 
182  bool create_area(osmium::memory::Buffer& out_buffer, const osmium::Relation& relation, const std::vector<const osmium::Way*>& members) {
183  set_num_members(members.size());
184  osmium::builder::AreaBuilder builder{out_buffer};
185  builder.initialize_from_object(relation);
186 
187  const bool area_okay = create_rings();
188  if (area_okay || config().create_empty_areas) {
189  add_tags_to_area(builder, relation);
190  }
191  if (area_okay) {
192  add_rings_to_area(builder);
193  }
194 
195  if (report_ways()) {
196  for (const osmium::Way* way : members) {
197  config().problem_reporter->report_way(*way);
198  }
199  }
200 
201  return area_okay || config().create_empty_areas;
202  }
203 
204  public:
205 
206  explicit AssemblerLegacy(const config_type& config) :
207  detail::BasicAssemblerWithTags(config) {
208  }
209 
210  ~AssemblerLegacy() noexcept = default;
211 
219  bool operator()(const osmium::Way& way, osmium::memory::Buffer& out_buffer) {
220  if (!config().create_way_polygons) {
221  return true;
222  }
223 
224  if (way.tags().has_tag("area", "no")) {
225  return true;
226  }
227 
228  if (config().problem_reporter) {
229  config().problem_reporter->set_object(osmium::item_type::way, way.id());
230  config().problem_reporter->set_nodes(way.nodes().size());
231  }
232 
233  // Ignore (but count) ways without segments.
234  if (way.nodes().size() < 2) {
235  ++stats().short_ways;
236  return false;
237  }
238 
239  if (!way.ends_have_same_id()) {
240  ++stats().duplicate_nodes;
241  if (config().problem_reporter) {
242  config().problem_reporter->report_duplicate_node(way.nodes().front().ref(), way.nodes().back().ref(), way.nodes().front().location());
243  }
244  }
245 
246  ++stats().from_ways;
247  stats().invalid_locations = segment_list().extract_segments_from_way(config().problem_reporter,
248  stats().duplicate_nodes,
249  way);
250  if (!config().ignore_invalid_locations && stats().invalid_locations > 0) {
251  return false;
252  }
253 
254  if (config().debug_level > 0) {
255  std::cerr << "\nAssembling way " << way.id() << " containing " << segment_list().size() << " nodes\n";
256  }
257 
258  // Now create the Area object and add the attributes and tags
259  // from the way.
260  const bool okay = create_area(out_buffer, way);
261  if (okay) {
262  out_buffer.commit();
263  } else {
264  out_buffer.rollback();
265  }
266 
267  if (debug()) {
268  std::cerr << "Done: " << stats() << "\n";
269  }
270 
271  return okay;
272  }
273 
281  bool operator()(const osmium::Relation& relation, const std::vector<const osmium::Way*>& members, osmium::memory::Buffer& out_buffer) {
282  assert(relation.members().size() >= members.size());
283 
284  if (config().problem_reporter) {
285  config().problem_reporter->set_object(osmium::item_type::relation, relation.id());
286  }
287 
288  if (relation.members().empty()) {
289  ++stats().no_way_in_mp_relation;
290  return false;
291  }
292 
293  ++stats().from_relations;
294  stats().invalid_locations = segment_list().extract_segments_from_ways(config().problem_reporter,
295  stats().duplicate_nodes,
296  stats().duplicate_ways,
297  relation,
298  members);
299  if (!config().ignore_invalid_locations && stats().invalid_locations > 0) {
300  return false;
301  }
302  stats().member_ways = members.size();
303 
304  if (stats().member_ways == 1) {
305  ++stats().single_way_in_mp_relation;
306  }
307 
308  if (config().debug_level > 0) {
309  std::cerr << "\nAssembling relation " << relation.id() << " containing " << members.size() << " way members with " << segment_list().size() << " nodes\n";
310  }
311 
312  const std::size_t area_offset = out_buffer.committed();
313 
314  // Now create the Area object and add the attributes and tags
315  // from the relation.
316  bool okay = create_area(out_buffer, relation, members);
317  if (okay) {
318  if ((config().create_new_style_polygons && stats().no_tags_on_relation == 0) ||
319  (config().create_old_style_polygons && stats().no_tags_on_relation != 0)) {
320  out_buffer.commit();
321  } else {
322  out_buffer.rollback();
323  }
324  } else {
325  out_buffer.rollback();
326  }
327 
328  const osmium::TagList& area_tags = out_buffer.get<osmium::Area>(area_offset).tags(); // tags of the area we just built
329 
330  // Find all closed ways that are inner rings and check their
331  // tags. If they are not the same as the tags of the area we
332  // just built, add them to a list and later build areas for
333  // them, too.
334  std::vector<const osmium::Way*> ways_that_should_be_areas;
335  if (stats().wrong_role == 0) {
336  detail::for_each_member(relation, members, [this, &ways_that_should_be_areas, &area_tags](const osmium::RelationMember& member, const osmium::Way& way) {
337  if (!std::strcmp(member.role(), "inner")) {
338  if (!way.nodes().empty() && way.is_closed() && way.tags().size() > 0) {
339  const auto d = std::count_if(way.tags().cbegin(), way.tags().cend(), std::cref(filter()));
340  if (d > 0) {
341  osmium::tags::KeyFilter::iterator way_fi_begin(std::cref(filter()), way.tags().cbegin(), way.tags().cend());
342  osmium::tags::KeyFilter::iterator way_fi_end(std::cref(filter()), way.tags().cend(), way.tags().cend());
343  osmium::tags::KeyFilter::iterator area_fi_begin(std::cref(filter()), area_tags.cbegin(), area_tags.cend());
344  osmium::tags::KeyFilter::iterator area_fi_end(std::cref(filter()), area_tags.cend(), area_tags.cend());
345 
346  if (!std::equal(way_fi_begin, way_fi_end, area_fi_begin) || d != std::distance(area_fi_begin, area_fi_end)) {
347  ways_that_should_be_areas.push_back(&way);
348  } else {
349  ++stats().inner_with_same_tags;
350  if (config().problem_reporter) {
351  config().problem_reporter->report_inner_with_same_tags(way);
352  }
353  }
354  }
355  }
356  }
357  });
358  }
359 
360  if (debug()) {
361  std::cerr << "Done: " << stats() << "\n";
362  }
363 
364  // Now build areas for all ways found in the last step.
365  for (const osmium::Way* way : ways_that_should_be_areas) {
366  AssemblerLegacy assembler{config()};
367  if (!assembler(*way, out_buffer)) {
368  okay = false;
369  }
370  stats() += assembler.stats();
371  }
372 
373  return okay;
374  }
375 
376  }; // class AssemblerLegacy
377 
378  } // namespace area
379 
380 } // namespace osmium
381 
382 #endif // OSMIUM_AREA_ASSEMBLER_LEGACY_HPP
WayNodeList & nodes()
Definition: way.hpp:89
std::size_t commit()
Definition: buffer.hpp:355
Definition: filter.hpp:94
bool operator()(const osmium::Relation &relation, const std::vector< const osmium::Way *> &members, osmium::memory::Buffer &out_buffer)
Definition: assembler_legacy.hpp:281
void add_item(const osmium::memory::Item &item)
Definition: builder.hpp:215
const TagList & tags() const
Get the list of tags for this object.
Definition: object.hpp:325
Definition: tag.hpp:107
RelationMemberList & members()
Get a reference to the member list.
Definition: relation.hpp:186
~AssemblerLegacy() noexcept=default
Definition: relation.hpp:168
Definition: area.hpp:126
const_iterator cbegin() const noexcept
Definition: collection.hpp:164
Filter & add(bool result, const key_type &key, const value_type &value)
Definition: filter.hpp:136
Definition: entity_bits.hpp:72
size_type size() const noexcept
Definition: collection.hpp:152
bool has_tag(const char *key, const char *value) const noexcept
Definition: tag.hpp:159
double distance(const osmium::geom::Coordinates &c1, const osmium::geom::Coordinates &c2)
Definition: haversine.hpp:66
bool is_closed() const
Definition: way.hpp:112
Definition: way.hpp:72
bool create_area(osmium::memory::Buffer &out_buffer, const osmium::Way &way)
Definition: assembler_legacy.hpp:163
std::size_t committed() const noexcept
Definition: buffer.hpp:268
bool create_area(osmium::memory::Buffer &out_buffer, const osmium::Relation &relation, const std::vector< const osmium::Way *> &members)
Definition: assembler_legacy.hpp:182
Filter< std::string > KeyFilter
Definition: filter.hpp:179
constexpr osmium::object_id_type ref() const noexcept
Definition: node_ref.hpp:65
bool empty() const noexcept
Definition: node_ref_list.hpp:74
Definition: relation.hpp:57
Namespace for everything in the Osmium library.
Definition: assembler.hpp:53
Definition: assembler_legacy.hpp:73
Definition: attr.hpp:333
Definition: assembler_legacy.hpp:102
T & get(const std::size_t offset) const
Definition: buffer.hpp:405
void add_common_tags(osmium::builder::TagListBuilder &tl_builder, std::set< const osmium::Way *> &ways) const
Definition: assembler_legacy.hpp:79
const_iterator cend() const noexcept
Definition: collection.hpp:168
bool empty() const noexcept
Definition: collection.hpp:143
bool operator()(const osmium::Way &way, osmium::memory::Buffer &out_buffer)
Definition: assembler_legacy.hpp:219
MPFilter()
Definition: assembler_legacy.hpp:104
AssemblerLegacy(const config_type &config)
Definition: assembler_legacy.hpp:206
osmium::Location & location() noexcept
Definition: node_ref.hpp:79
object_id_type id() const noexcept
Get ID of this object.
Definition: object.hpp:126
void add_tags_to_area(osmium::builder::AreaBuilder &builder, const osmium::Way &way) const
Definition: assembler_legacy.hpp:75
bool ends_have_same_id() const
Definition: way.hpp:116
Definition: buffer.hpp:98
const char * role() const noexcept
Definition: relation.hpp:138
const NodeRef & front() const noexcept
Definition: node_ref_list.hpp:126
static const MPFilter & filter() noexcept
Definition: assembler_legacy.hpp:115
const NodeRef & back() const noexcept
Definition: node_ref_list.hpp:138
size_t count() const noexcept
Definition: filter.hpp:160
void rollback()
Definition: buffer.hpp:371
size_type size() const noexcept
Definition: node_ref_list.hpp:83
void add_tags_to_area(osmium::builder::AreaBuilder &builder, const osmium::Relation &relation)
Definition: assembler_legacy.hpp:120
void add_tag(const char *key, const char *value)
Definition: osm_object_builder.hpp:98
boost::filter_iterator< filter_type, osmium::TagList::const_iterator > iterator
Definition: filter.hpp:129
Definition: osm_object_builder.hpp:74
Definition: osm_object_builder.hpp:540