1 #ifndef OSMIUM_AREA_ASSEMBLER_HPP 2 #define OSMIUM_AREA_ASSEMBLER_HPP 46 #include <unordered_map> 47 #include <unordered_set> 60 #include <osmium/area/detail/proto_ring.hpp> 61 #include <osmium/area/detail/node_ref_segment.hpp> 62 #include <osmium/area/detail/segment_list.hpp> 146 problem_reporter(pr),
164 using open_ring_its_type = std::list<std::list<detail::ProtoRing>::iterator>;
166 struct location_to_ring_map {
168 open_ring_its_type::iterator ring_it;
171 location_to_ring_map(
const osmium::Location& l,
const open_ring_its_type::iterator& r,
bool s) noexcept :
183 const detail::ProtoRing& ring()
const noexcept {
189 inline bool operator==(
const location_to_ring_map& a,
const location_to_ring_map& b) noexcept {
190 return a.location == b.location;
193 inline bool operator<(
const location_to_ring_map& a,
const location_to_ring_map& b) noexcept {
194 return a.location < b.location;
210 static constexpr
const uint32_t invalid_item = 1 << 30;
213 uint32_t reverse : 1;
220 explicit slocation(uint32_t n,
bool r =
false) noexcept :
226 const auto& segment = segment_list[item];
227 return reverse ? segment.second().location() : segment.first().location();
231 const auto& segment = segment_list[item];
232 return reverse ? segment.second() : segment.first();
236 if (item == invalid_item) {
237 return default_location;
239 return location(segment_list);
285 std::map<std::string, size_t> counter;
287 for (
const auto& tag : way->tags()) {
288 std::string kv {tag.key()};
290 kv.append(tag.value());
295 const size_t num_ways = ways.size();
296 for (
const auto& t_c : counter) {
298 std::cerr <<
" tag " << t_c.first <<
" is used " << t_c.second <<
" times in " << num_ways <<
" ways\n";
300 if (t_c.second == num_ways) {
301 const size_t len = std::strlen(t_c.first.c_str());
302 tl_builder.
add_tag(t_c.first.c_str(), t_c.first.c_str() + len + 1);
311 add(
false,
"created_by");
312 add(
false,
"source");
314 add(
false,
"test:id");
315 add(
false,
"test:section");
328 if (std::strcmp(tag.key(),
"type")) {
329 tl_builder.
add_tag(tag.key(), tag.value());
335 const auto count = std::count_if(relation.
tags().
cbegin(), relation.
tags().
cend(), filter());
338 std::cerr <<
" found " << count <<
" tags on relation (without ignored ones)\n";
343 std::cerr <<
" use tags from relation\n";
349 copy_tags_without_type(builder, relation.
tags());
354 std::cerr <<
" use tags from outer ways\n";
356 std::set<const osmium::Way*> ways;
357 for (
const auto& ring : m_rings) {
358 if (ring.is_outer()) {
362 if (ways.size() == 1) {
364 std::cerr <<
" only one outer way\n";
366 builder.
add_item(&(*ways.cbegin())->tags());
369 std::cerr <<
" multiple outer ways, get common tags\n";
372 add_common_tags(tl_builder, ways);
377 template <
typename TBuilder>
379 TBuilder ring_builder(builder.
buffer(), &builder);
380 ring_builder.add_node_ref(ring.get_node_ref_start());
381 for (
const auto& segment : ring.segments()) {
382 ring_builder.add_node_ref(segment->stop());
391 for (
const detail::ProtoRing& ring : m_rings) {
392 if (ring.is_outer()) {
393 build_ring_from_proto_ring<osmium::builder::OuterRingBuilder>(builder, ring);
394 for (
const detail::ProtoRing* inner : ring.inner_rings()) {
395 build_ring_from_proto_ring<osmium::builder::InnerRingBuilder>(builder, *inner);
403 std::cerr <<
" Checking inner/outer roles\n";
406 std::unordered_map<const osmium::Way*, const detail::ProtoRing*> way_rings;
407 std::unordered_set<const osmium::Way*> ways_in_multiple_rings;
409 for (
const detail::ProtoRing& ring : m_rings) {
410 for (
const auto& segment : ring.segments()) {
411 assert(segment->way());
413 if (!segment->role_empty() && (ring.is_outer() ? !segment->role_outer() : !segment->role_inner())) {
416 std::cerr <<
" Segment " << *segment <<
" from way " << segment->way()->id() <<
" has role '" << segment->role_name()
417 <<
"', but should have role '" << (ring.is_outer() ?
"outer" :
"inner") <<
"'\n";
420 if (ring.is_outer()) {
428 auto& r = way_rings[segment->way()];
431 }
else if (r != &ring) {
432 ways_in_multiple_rings.insert(segment->way());
438 for (
const osmium::Way* way : ways_in_multiple_rings) {
441 std::cerr <<
" Way " << way->id() <<
" is in multiple rings\n";
451 auto it = std::lower_bound(m_locations.begin(), m_locations.end(),
slocation{}, [
this, &location](
const slocation& a,
const slocation& b) {
452 return a.
location(m_segment_list, location) < b.location(m_segment_list, location);
455 assert(it != m_locations.end());
456 if (m_segment_list[it->item].is_done()) {
459 assert(it != m_locations.end());
461 assert(!m_segment_list[it->item].is_done());
462 return &m_segment_list[it->item];
474 m_ring_ptr(ring_ptr) {
477 int32_t
y() const noexcept {
481 const detail::ProtoRing&
ring() const noexcept {
490 return m_ring_ptr == rhs.m_ring_ptr;
494 return m_y < rhs.m_y;
503 const auto it = std::adjacent_find(outer_rings.begin(), outer_rings.end());
504 if (it == outer_rings.end()) {
507 outer_rings.erase(it, std::next(it, 2));
513 std::cerr <<
" Looking for ring enclosing " << *segment <<
"\n";
516 const auto location = segment->first().location();
517 const auto end_location = segment->second().location();
519 while (segment->first().location() == location) {
520 if (segment == &m_segment_list.back()) {
529 while (segment >= &m_segment_list.front()) {
530 if (!segment->is_direction_done()) {
535 std::cerr <<
" Checking against " << *segment <<
"\n";
540 if (segment->first().location() == location) {
541 const int64_t ax = a.
x();
542 const int64_t bx = b.
x();
543 const int64_t lx = end_location.x();
544 const int64_t ay = a.
y();
545 const int64_t by = b.
y();
546 const int64_t ly = end_location.y();
547 const auto z = (bx - ax)*(ly - ay) - (by - ay)*(lx - ax);
549 std::cerr <<
" Segment XXXX z=" << z <<
"\n";
552 nesting += segment->is_reverse() ? -1 : 1;
554 std::cerr <<
" Segment is below (nesting=" << nesting <<
")\n";
556 if (segment->ring()->is_outer()) {
558 std::cerr <<
" Segment belongs to outer ring\n";
560 outer_rings.emplace_back(a.
y(), segment->ring());
563 }
else if (a.
x() <= location.x() && location.x() < b.
x()) {
565 std::cerr <<
" Is in x range\n";
568 const int64_t ax = a.
x();
569 const int64_t bx = b.
x();
570 const int64_t lx = location.x();
571 const int64_t ay = a.
y();
572 const int64_t by = b.
y();
573 const int64_t ly = location.y();
574 const auto z = (bx - ax)*(ly - ay) - (by - ay)*(lx - ax);
577 nesting += segment->is_reverse() ? -1 : 1;
579 std::cerr <<
" Segment is below (nesting=" << nesting <<
")\n";
581 if (segment->ring()->is_outer()) {
583 std::cerr <<
" Segment belongs to outer ring\n";
585 int32_t y = int32_t(ay + (by - ay) * (lx - ax) / (bx - ax));
586 outer_rings.emplace_back(y, segment->ring());
593 if (nesting % 2 == 0) {
595 std::cerr <<
" Decided that this is an outer ring\n";
600 std::cerr <<
" Decided that this is an inner ring\n";
602 assert(!outer_rings.empty());
604 std::sort(outer_rings.rbegin(), outer_rings.rend());
606 for (
const auto& o : outer_rings) {
607 std::cerr <<
" y=" << o.y() <<
" " << o.ring() <<
"\n";
611 remove_duplicates(outer_rings);
613 std::cerr <<
" after remove duplicates:\n";
614 for (
const auto& o : outer_rings) {
615 std::cerr <<
" y=" << o.y() <<
" " << o.ring() <<
"\n";
619 assert(!outer_rings.empty());
620 return outer_rings.front().ring_ptr();
625 return std::find(m_split_locations.cbegin(), m_split_locations.cend(), location) != m_split_locations.cend();
629 detail::NodeRefSegment* segment = &m_segment_list[node.
item];
630 assert(!segment->is_done());
633 std::cerr <<
" Starting new ring at location " << node.
location(m_segment_list) <<
" with segment " << *segment <<
"\n";
642 if (segment != &m_segment_list.front()) {
643 outer_ring = find_enclosing_ring(segment);
645 segment->mark_direction_done();
647 m_rings.emplace_back(segment);
648 detail::ProtoRing* ring = &m_rings.back();
651 std::cerr <<
" This is an inner ring. Outer ring is " << *outer_ring <<
"\n";
653 outer_ring->add_inner_ring(ring);
654 ring->set_outer_ring(outer_ring);
655 }
else if (debug()) {
656 std::cerr <<
" This is an outer ring\n";
663 while (first_location != last_location) {
665 detail::NodeRefSegment* next_segment = get_next_segment(last_location);
666 next_segment->mark_direction_done();
667 if (next_segment->start().location() != last_location) {
668 next_segment->reverse();
670 ring->add_segment_back(next_segment);
672 std::cerr <<
" Next segment is " << *next_segment <<
"\n";
674 last_location = next_segment->stop().location();
677 ring->fix_direction();
680 std::cerr <<
" Completed ring: " << *ring <<
"\n";
687 detail::NodeRefSegment* segment = &m_segment_list[node.
item];
688 assert(!segment->is_done());
691 std::cerr <<
" Starting new ring at location " << node.
location(m_segment_list) <<
" with segment " << *segment <<
"\n";
698 m_rings.emplace_back(segment);
699 detail::ProtoRing* ring = &m_rings.back();
705 while (first_location != last_location && !is_split_location(last_location)) {
707 detail::NodeRefSegment* next_segment = get_next_segment(last_location);
708 if (next_segment->start().location() != last_location) {
709 next_segment->reverse();
711 ring->add_segment_back(next_segment);
713 std::cerr <<
" Next segment is " << *next_segment <<
"\n";
715 last_location = next_segment->stop().location();
719 if (first_location == last_location) {
720 std::cerr <<
" Completed ring: " << *ring <<
"\n";
722 std::cerr <<
" Completed partial ring: " << *ring <<
"\n";
730 m_locations.reserve(m_segment_list.size() * 2);
732 for (uint32_t n = 0; n < m_segment_list.size(); ++n) {
733 m_locations.emplace_back(n,
false);
734 m_locations.emplace_back(n,
true);
737 std::stable_sort(m_locations.begin(), m_locations.end(), [
this](
const slocation& a,
const slocation& b) {
738 return a.
location(m_segment_list) < b.location(m_segment_list);
743 detail::ProtoRing*
outer_ring = find_enclosing_ring(ring->min_segment());
745 outer_ring->add_inner_ring(ring);
746 ring->set_outer_ring(outer_ring);
748 ring->fix_direction();
749 ring->mark_direction_done();
754 std::cerr <<
" Finding inner/outer rings\n";
756 std::vector<detail::ProtoRing*> rings;
757 rings.reserve(m_rings.size());
758 for (
auto& ring : m_rings) {
760 rings.push_back(&ring);
768 std::sort(rings.begin(), rings.end(), [](detail::ProtoRing* a, detail::ProtoRing* b) {
769 return a->min_segment() < b->min_segment();
772 rings.front()->fix_direction();
773 rings.front()->mark_direction_done();
775 std::cerr <<
" First ring is outer: " << *rings.front() <<
"\n";
777 for (
auto it = std::next(rings.begin()); it != rings.end(); ++it) {
779 std::cerr <<
" Checking (at min segment " << *((*it)->min_segment()) <<
") ring " << **it <<
"\n";
781 find_inner_outer_complex(*it);
783 std::cerr <<
" Ring is " << ((*it)->is_outer() ?
"OUTER: " :
"INNER: ") << **it <<
"\n";
795 for (
auto it = m_locations.cbegin(); it != m_locations.cend(); ++it) {
798 if (std::next(it) == m_locations.cend() || loc != std::next(it)->location(m_segment_list)) {
800 std::cerr <<
" Found open ring at " << nr <<
"\n";
803 const auto& segment = m_segment_list[it->item];
808 if (loc == previous_location && (m_split_locations.empty() || m_split_locations.back() != previous_location )) {
809 m_split_locations.push_back(previous_location);
812 if (it == m_locations.end()) {
816 previous_location = loc;
822 uint32_t count_remaining = m_segment_list.size();
824 const detail::NodeRefSegment& segment = m_segment_list[sl.item];
825 if (!segment.is_done()) {
826 count_remaining -= add_new_ring(sl);
827 if (count_remaining == 0) {
835 std::vector<location_to_ring_map> xrings;
836 xrings.reserve(open_ring_its.size() * 2);
838 for (
auto it = open_ring_its.begin(); it != open_ring_its.end(); ++it) {
840 std::cerr <<
" Ring: " << **it <<
"\n";
842 xrings.emplace_back((*it)->get_node_ref_start().location(), it,
true);
843 xrings.emplace_back((*it)->get_node_ref_stop().location(), it,
false);
846 std::sort(xrings.begin(), xrings.end());
852 auto& r1 = *m1.ring_it;
853 auto& r2 = *m2.ring_it;
855 if (r1->get_node_ref_stop().location() == r2->get_node_ref_start().location()) {
856 r1->join_forward(*r2);
857 }
else if (r1->get_node_ref_stop().location() == r2->get_node_ref_stop().location()) {
858 r1->join_backward(*r2);
859 }
else if (r1->get_node_ref_start().location() == r2->get_node_ref_start().location()) {
861 r1->join_forward(*r2);
862 }
else if (r1->get_node_ref_start().location() == r2->get_node_ref_stop().location()) {
864 r1->join_backward(*r2);
870 open_ring_its.remove(r2);
873 open_ring_its.remove(r1);
878 if (open_ring_its.empty()) {
883 std::cerr <<
" Trying to merge " << open_ring_its.size() <<
" open rings\n";
886 std::vector<location_to_ring_map> xrings = create_location_to_ring_map(open_ring_its);
888 auto it = xrings.cbegin();
889 while (it != xrings.cend()) {
890 it = std::adjacent_find(it, xrings.cend());
891 if (it == xrings.cend()) {
894 auto after = std::next(it, 2);
895 if (after == xrings.cend() || after->location != it->location) {
897 std::cerr <<
" Merging two rings\n";
899 merge_two_rings(open_ring_its, *it, *std::next(it));
902 while (it != xrings.cend() && it->location == after->location) {
911 return std::any_of(m_rings.cbegin(), m_rings.cend(), [](
const detail::ProtoRing& ring){
912 return !ring.closed();
918 std::vector<std::pair<location_to_ring_map, bool>>
rings;
923 sum(ring.ring().sum()),
925 start_location(ring.ring().get_node_ref_start().location()),
926 stop_location(ring.ring().get_node_ref_stop().location()) {
927 rings.emplace_back(ring, reverse);
931 return start_location == stop_location;
936 void find_candidates(std::vector<candidate>& candidates, std::unordered_set<osmium::Location>& loc_done,
const std::vector<location_to_ring_map>& xrings,
candidate& cand) {
939 for (
const auto& ring : cand.
rings) {
940 std::cerr <<
" " << ring.first.ring() << (ring.second ?
" reverse" :
"") <<
"\n";
944 const auto connections =
make_range(std::equal_range(xrings.cbegin(),
948 assert(connections.begin() != connections.end());
950 assert(!cand.
rings.empty());
951 const detail::ProtoRing* ring_leading_here = &cand.
rings.back().first.ring();
953 const detail::ProtoRing& ring = m.ring();
955 if (&ring != ring_leading_here) {
957 std::cerr <<
" next possible connection: " << ring << (m.start ?
"" :
" reverse") <<
"\n";
962 c.
rings.emplace_back(m,
false);
963 c.stop_location = ring.get_node_ref_stop().location();
966 c.rings.emplace_back(m,
true);
967 c.stop_location = ring.get_node_ref_start().location();
972 std::cerr <<
" found candidate\n";
974 candidates.push_back(c);
975 }
else if (loc_done.count(c.stop_location) == 0) {
977 std::cerr <<
" recurse...\n";
979 loc_done.insert(c.stop_location);
980 find_candidates(candidates, loc_done, xrings, c);
982 std::cerr <<
" ...back\n";
984 }
else if (debug()) {
985 std::cerr <<
" loop found\n";
1000 assert(!open_ring_its.empty());
1003 std::cerr <<
" Trying to merge " << open_ring_its.size() <<
" open rings\n";
1006 std::vector<location_to_ring_map> xrings = create_location_to_ring_map(open_ring_its);
1009 return a.ring().min_segment() < b.ring().min_segment();
1012 find_inner_outer_complex();
1013 detail::ProtoRing*
outer_ring = find_enclosing_ring(ring_min->ring().min_segment());
1014 bool ring_min_is_outer = !outer_ring;
1016 std::cerr <<
" Open ring is " << (ring_min_is_outer ?
"outer" :
"inner") <<
" ring\n";
1018 for (
auto& ring : m_rings) {
1026 std::unordered_set<osmium::Location> loc_done;
1028 loc_done.insert(cand.stop_location);
1030 std::vector<candidate> candidates;
1031 find_candidates(candidates, loc_done, xrings, cand);
1033 if (candidates.empty()) {
1035 std::cerr <<
" Found no candidates\n";
1037 if (!open_ring_its.empty()) {
1040 for (
auto& it : open_ring_its) {
1050 std::cerr <<
" Found candidates:\n";
1051 for (
const auto& cand : candidates) {
1052 std::cerr <<
" sum=" << cand.sum <<
"\n";
1053 for (
const auto& ring : cand.rings) {
1054 std::cerr <<
" " << ring.first.ring() << (ring.second ?
" reverse" :
"") <<
"\n";
1060 auto chosen_cand = ring_min_is_outer ?
1061 std::min_element(candidates.cbegin(), candidates.cend(), [](
const candidate& a,
const candidate& b) {
1062 return std::abs(a.
sum) < std::abs(b.sum);
1064 std::max_element(candidates.cbegin(), candidates.cend(), [](
const candidate& a,
const candidate& b) {
1065 return std::abs(a.
sum) < std::abs(b.sum);
1069 std::cerr <<
" Decided on: sum=" << chosen_cand->sum <<
"\n";
1070 for (
const auto& ring : chosen_cand->rings) {
1071 std::cerr <<
" " << ring.first.ring() << (ring.second ?
" reverse" :
"") <<
"\n";
1076 assert(chosen_cand->rings.size() > 1);
1077 const auto& first_ring = chosen_cand->rings.front().first;
1078 for (
auto it = chosen_cand->rings.begin() + 1; it != chosen_cand->rings.end(); ++it) {
1079 merge_two_rings(open_ring_its, first_ring, it->first);
1083 std::cerr <<
" Merged to " << first_ring.ring() <<
"\n";
1091 uint32_t count_remaining = m_segment_list.size();
1093 const auto locs =
make_range(std::equal_range(m_locations.begin(),
1097 return a.
location(m_segment_list, location) < b.location(m_segment_list, location);
1099 for (
auto& loc : locs) {
1100 if (!m_segment_list[loc.item].is_done()) {
1101 count_remaining -= add_new_ring_complex(loc);
1102 if (count_remaining == 0) {
1110 if (count_remaining > 0) {
1112 const detail::NodeRefSegment& segment = m_segment_list[sl.item];
1113 if (!segment.is_done()) {
1114 count_remaining -= add_new_ring_complex(sl);
1115 if (count_remaining == 0) {
1126 if (there_are_open_rings()) {
1130 for (
auto it = m_rings.begin(); it != m_rings.end(); ++it) {
1131 if (!it->closed()) {
1132 open_ring_its.push_back(it);
1136 while (!open_ring_its.empty()) {
1138 std::cerr <<
" There are " << open_ring_its.size() <<
" open rings\n";
1140 while (try_to_merge(open_ring_its));
1142 if (!open_ring_its.empty()) {
1144 std::cerr <<
" After joining obvious cases there are still " << open_ring_its.size() <<
" open rings\n";
1146 if (!join_connected_rings(open_ring_its)) {
1153 std::cerr <<
" Joined all open rings\n";
1159 find_inner_outer_complex();
1168 m_stats.
nodes += m_segment_list.size();
1173 m_segment_list.sort();
1185 if (m_segment_list.empty()) {
1187 std::cerr <<
" No segments left\n";
1193 std::cerr <<
"Sorted de-duplicated segment list:\n";
1194 for (
const auto& s : m_segment_list) {
1195 std::cerr <<
" " << s <<
"\n";
1205 timer_intersection.
stop();
1216 create_locations_list();
1217 timer_locations_list.
stop();
1224 if (!find_split_locations()) {
1231 if (!m_split_locations.empty()) {
1233 std::cerr <<
" Found split locations:\n";
1235 for (
const auto& location : m_split_locations) {
1237 auto it = std::lower_bound(m_locations.cbegin(), m_locations.cend(),
slocation{}, [
this, &location](
const slocation& a,
const slocation& b) {
1238 return a.
location(m_segment_list, location) < b.location(m_segment_list, location);
1240 assert(it != m_locations.cend());
1245 std::cerr <<
" " << location <<
"\n";
1256 if (m_split_locations.empty()) {
1258 std::cerr <<
" No split locations -> using simple algorithm\n";
1262 timer_simple_case.
start();
1263 create_rings_simple_case();
1264 timer_simple_case.
stop();
1267 std::cerr <<
" Found split locations -> using complex algorithm\n";
1271 timer_complex_case.
start();
1272 if (!create_rings_complex_case()) {
1275 timer_complex_case.
stop();
1282 check_inner_outer_roles();
1286 m_stats.
outer_rings = std::count_if(m_rings.cbegin(), m_rings.cend(), [](
const detail::ProtoRing& ring){
1287 return ring.is_outer();
1291 #ifdef OSMIUM_WITH_TIMER 1299 if (m_split_locations.empty()) {
1303 std::cout <<
" 0" <<
1308 # ifdef OSMIUM_AREA_CHECK_INNER_OUTER_ROLES 1309 ' ' << timer_roles.elapsed_microseconds() <<
1319 #ifdef OSMIUM_WITH_TIMER 1320 static bool print_header() {
1321 std::cout <<
"nodes outer_rings inner_rings sort dupl intersection locations split simple_case complex_case roles_check\n";
1325 static bool init_header() {
1326 static bool printed_print_header = print_header();
1327 return printed_print_header;
1335 const bool area_okay = create_rings();
1337 add_tags_to_area(builder, way);
1340 add_rings_to_area(builder);
1343 if (report_ways()) {
1354 const bool area_okay = create_rings();
1356 add_tags_to_area(builder, relation);
1359 add_rings_to_area(builder);
1362 if (report_ways()) {
1378 #ifdef OSMIUM_WITH_TIMER 1420 std::cerr <<
"\nAssembling way " << way.
id() <<
" containing " << m_segment_list.size() <<
" nodes\n";
1425 if (create_area(out_buffer, way)) {
1432 std::cerr <<
"Done: " << m_stats <<
"\n";
1447 std::vector<const osmium::Way*> ways;
1448 for (
size_t offset : members) {
1450 ways.push_back(&way);
1452 operator()(relation, ways, out_buffer);
1460 assert(relation.
members().
size() >= members.size());
1480 std::cerr <<
"\nAssembling relation " << relation.
id() <<
" containing " << members.size() <<
" way members with " << m_segment_list.size() <<
" nodes\n";
1483 const size_t area_offset = out_buffer.
committed();
1487 if (create_area(out_buffer, relation, members)) {
1504 std::vector<const osmium::Way*> ways_that_should_be_areas;
1507 if (!std::strcmp(member.
role(),
"inner")) {
1516 if (!std::equal(way_fi_begin, way_fi_end, area_fi_begin) || d !=
std::distance(area_fi_begin, area_fi_end)) {
1517 ways_that_should_be_areas.push_back(&way);
1531 std::cerr <<
"Done: " << m_stats <<
"\n";
1535 for (
const osmium::Way* way : ways_that_should_be_areas) {
1537 assembler(*way, out_buffer);
1555 #endif // OSMIUM_AREA_ASSEMBLER_HPP area_stats m_stats
Definition: assembler.hpp:260
WayNodeList & nodes()
Definition: way.hpp:75
detail::location_to_ring_map location_to_ring_map
Definition: assembler.hpp:206
bool empty() const
Definition: collection.hpp:131
osmium::area::ProblemReporter * problem_reporter
Definition: assembler.hpp:80
#define OSMIUM_DEPRECATED
Definition: compatibility.hpp:50
osmium::memory::Buffer & buffer() noexcept
Return the buffer this builder is using.
Definition: builder.hpp:179
rings_stack_element(int32_t y, detail::ProtoRing *ring_ptr)
Definition: assembler.hpp:472
iterator_range< It > make_range(P &&p)
Definition: iterator.hpp:76
int64_t sum
Definition: assembler.hpp:917
RelationMemberList & members()
Definition: relation.hpp:177
virtual void report_way_in_multiple_rings(const osmium::Way &way)
Definition: problem_reporter.hpp:178
int32_t y() const noexcept
Definition: assembler.hpp:477
uint64_t member_ways
Number of ways in the area.
Definition: stats.hpp:60
uint64_t area_really_complex_case
Most difficult case with rings touching in multiple points.
Definition: stats.hpp:50
virtual void report_duplicate_node(osmium::object_id_type node_id1, osmium::object_id_type node_id2, osmium::Location location)
Definition: problem_reporter.hpp:104
const_iterator cend() const
Definition: collection.hpp:147
static void copy_tags_without_type(osmium::builder::AreaBuilder &builder, const osmium::TagList &tags)
Definition: assembler.hpp:325
uint64_t wrong_role
Member has wrong role (not "outer", "inner", or empty)
Definition: stats.hpp:70
virtual void report_role_should_be_inner(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end)
Definition: problem_reporter.hpp:170
void initialize_from_object(const osmium::OSMObject &source)
Definition: osm_object_builder.hpp:387
void add_rings_to_area(osmium::builder::AreaBuilder &builder) const
Definition: assembler.hpp:390
constexpr bool operator==(const Box &lhs, const Box &rhs) noexcept
Definition: box.hpp:222
bool ends_have_same_id() const
Definition: way.hpp:102
void operator()(const osmium::Way &way, osmium::memory::Buffer &out_buffer)
Definition: assembler.hpp:1389
Definition: relation.hpp:165
virtual void report_way(const osmium::Way &way)
Definition: problem_reporter.hpp:196
AssemblerConfig() noexcept=default
size_type size() const noexcept
Definition: relation.hpp:158
void start()
Definition: timer.hpp:82
static const MPFilter & filter() noexcept
Definition: assembler.hpp:320
uint64_t no_way_in_mp_relation
Multipolygon relation with no way members.
Definition: stats.hpp:62
void operator()(const osmium::Relation &relation, const std::vector< const osmium::Way * > &members, osmium::memory::Buffer &out_buffer)
Definition: assembler.hpp:1459
Definition: assembler.hpp:75
Definition: entity_bits.hpp:70
void add_tags_to_area(osmium::builder::AreaBuilder &builder, const osmium::Relation &relation)
Definition: assembler.hpp:334
uint64_t outer_rings
Number of outer rings in the area.
Definition: stats.hpp:65
candidate(location_to_ring_map &ring, bool reverse)
Definition: assembler.hpp:922
bool there_are_open_rings() const noexcept
Definition: assembler.hpp:910
double distance(const osmium::geom::Coordinates &c1, const osmium::geom::Coordinates &c2)
Definition: haversine.hpp:64
bool create_rings_complex_case()
Definition: assembler.hpp:1089
void remove_duplicates(rings_stack &outer_rings)
Definition: assembler.hpp:501
std::list< detail::ProtoRing > m_rings
Definition: assembler.hpp:251
osmium::Location stop_location
Definition: assembler.hpp:920
void add_common_tags(osmium::builder::TagListBuilder &tl_builder, std::set< const osmium::Way * > &ways) const
Definition: assembler.hpp:284
bool report_ways() const noexcept
Definition: assembler.hpp:266
Definition: assembler.hpp:465
bool create_area(osmium::memory::Buffer &out_buffer, const osmium::Relation &relation, const std::vector< const osmium::Way * > &members)
Definition: assembler.hpp:1350
std::vector< location_to_ring_map > create_location_to_ring_map(open_ring_its_type &open_ring_its)
Definition: assembler.hpp:834
slocation() noexcept
Definition: assembler.hpp:215
bool create_way_polygons
Definition: assembler.hpp:130
bool create_area(osmium::memory::Buffer &out_buffer, const osmium::Way &way)
Definition: assembler.hpp:1331
const AssemblerConfig & m_config
Definition: assembler.hpp:245
uint64_t short_ways
Number of ways with less than two nodes.
Definition: stats.hpp:66
virtual void report_role_should_be_outer(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end)
Definition: problem_reporter.hpp:160
uint64_t duplicate_segments
Segments duplicated (going back and forth)
Definition: stats.hpp:54
std::vector< slocation > m_locations
Definition: assembler.hpp:254
osmium::area::detail::SegmentList m_segment_list
Definition: assembler.hpp:248
size_type size() const noexcept
Definition: tag.hpp:125
bool operator<(const Changeset &lhs, const Changeset &rhs)
Definition: changeset.hpp:438
Definition: relation.hpp:54
const char * role() const noexcept
Definition: relation.hpp:134
void find_inner_outer_complex()
Definition: assembler.hpp:752
bool check_roles
Definition: assembler.hpp:97
Namespace for everything in the Osmium library.
Definition: assembler.hpp:66
void check_inner_outer_roles()
Definition: assembler.hpp:401
uint32_t item
Definition: assembler.hpp:212
uint64_t from_relations
Area created from multipolygon relation.
Definition: stats.hpp:55
uint64_t area_touching_rings_case
More difficult case with touching rings.
Definition: stats.hpp:52
Definition: assembler.hpp:208
uint64_t from_ways
Area created from way.
Definition: stats.hpp:56
OSMIUM_DEPRECATED void enable_debug_output(bool d=true)
Definition: assembler.hpp:156
const osmium::area::area_stats & stats() const noexcept
Definition: assembler.hpp:1545
Definition: problem_reporter.hpp:58
bool create_new_style_polygons
Definition: assembler.hpp:115
slocation(uint32_t n, bool r=false) noexcept
Definition: assembler.hpp:220
bool join_connected_rings(open_ring_its_type &open_ring_its)
Definition: assembler.hpp:999
bool operator==(const rings_stack_element &rhs) const noexcept
Definition: assembler.hpp:489
void set_object(osmium::item_type object_type, osmium::object_id_type object_id) noexcept
Definition: problem_reporter.hpp:83
detail::NodeRefSegment * get_next_segment(const osmium::Location &location)
Definition: assembler.hpp:450
void create_rings_simple_case()
Definition: assembler.hpp:821
void find_candidates(std::vector< candidate > &candidates, std::unordered_set< osmium::Location > &loc_done, const std::vector< location_to_ring_map > &xrings, candidate &cand)
Definition: assembler.hpp:936
Definition: assembler.hpp:307
constexpr osmium::object_id_type ref() const noexcept
Definition: node_ref.hpp:65
int64_t object_id_type
Type for OSM object (node, way, or relation) IDs.
Definition: types.hpp:45
void merge_two_rings(open_ring_its_type &open_ring_its, const location_to_ring_map &m1, const location_to_ring_map &m2)
Definition: assembler.hpp:851
std::vector< std::pair< location_to_ring_map, bool > > rings
Definition: assembler.hpp:918
const TagList & tags() const
Get the list of tags for this object.
Definition: object.hpp:297
void create_locations_list()
Definition: assembler.hpp:729
bool keep_type_tag
Definition: assembler.hpp:137
int debug_level
Definition: assembler.hpp:87
uint32_t add_new_ring(slocation &node)
Definition: assembler.hpp:628
void set_nodes(size_t nodes) noexcept
Definition: problem_reporter.hpp:88
size_t committed() const noexcept
Definition: buffer.hpp:241
int32_t m_y
Definition: assembler.hpp:467
const NodeRef & front() const noexcept
Definition: node_ref_list.hpp:92
virtual void report_touching_ring(osmium::object_id_type node_id, osmium::Location location)
Definition: problem_reporter.hpp:114
osmium::Location start_location
Definition: assembler.hpp:919
void add_tags_to_area(osmium::builder::AreaBuilder &builder, const osmium::Way &way) const
Definition: assembler.hpp:280
int64_t elapsed_microseconds() const
Definition: timer.hpp:88
uint64_t inner_with_same_tags
Number of inner ways with same tags as area.
Definition: stats.hpp:58
Assembler(const config_type &config)
Definition: assembler.hpp:1375
Definition: location.hpp:246
std::vector< rings_stack_element > rings_stack
Definition: assembler.hpp:499
uint64_t intersections
Number of intersections between segments.
Definition: stats.hpp:59
osmium::Location & location() noexcept
Definition: node_ref.hpp:79
detail::ProtoRing * m_ring_ptr
Definition: assembler.hpp:468
void stop()
Definition: timer.hpp:85
uint64_t inner_rings
Number of inner rings.
Definition: stats.hpp:57
const detail::ProtoRing & ring() const noexcept
Definition: assembler.hpp:481
Definition: assembler.hpp:916
virtual void report_ring_not_closed(const osmium::NodeRef &nr, const osmium::Way *way=nullptr)
Definition: problem_reporter.hpp:150
uint64_t ways_in_multiple_rings
Different segments of a way ended up in different rings.
Definition: stats.hpp:69
detail::open_ring_its_type open_ring_its_type
Definition: assembler.hpp:205
bool is_split_location(const osmium::Location &location) const noexcept
Definition: assembler.hpp:624
bool find_split_locations()
Definition: assembler.hpp:793
Definition: buffer.hpp:97
const osmium::NodeRef & node_ref(const detail::SegmentList &segment_list) const noexcept
Definition: assembler.hpp:230
T & get(const size_t offset) const
Definition: buffer.hpp:379
uint64_t open_rings
Number of open rings in the area.
Definition: stats.hpp:64
uint64_t no_tags_on_relation
No tags on relation (old-style multipolygon with tags on outer ways)
Definition: stats.hpp:61
void find_inner_outer_complex(detail::ProtoRing *ring)
Definition: assembler.hpp:742
static void build_ring_from_proto_ring(osmium::builder::AreaBuilder &builder, const detail::ProtoRing &ring)
Definition: assembler.hpp:378
object_id_type id() const noexcept
Get ID of this object.
Definition: object.hpp:112
uint64_t nodes
Number of nodes in the area.
Definition: stats.hpp:63
bool has_tag(const char *key, const char *value) const noexcept
Definition: tag.hpp:167
constexpr int32_t x() const noexcept
Definition: location.hpp:328
uint64_t single_way_in_mp_relation
Multipolygon relation containing a single way.
Definition: stats.hpp:67
bool create_rings()
Definition: assembler.hpp:1167
bool is_closed() const
Definition: way.hpp:98
const_iterator cbegin() const
Definition: collection.hpp:143
virtual void report_inner_with_same_tags(const osmium::Way &way)
Definition: problem_reporter.hpp:187
uint32_t add_new_ring_complex(slocation &node)
Definition: assembler.hpp:686
bool closed() const noexcept
Definition: assembler.hpp:930
void add_item(const osmium::memory::Item *item)
Definition: builder.hpp:127
MPFilter()
Definition: assembler.hpp:309
osmium::Location location(const detail::SegmentList &segment_list, const osmium::Location &default_location) const noexcept
Definition: assembler.hpp:235
size_t size() const noexcept
Definition: node_ref_list.hpp:68
osmium::Location location(const detail::SegmentList &segment_list) const noexcept
Definition: assembler.hpp:225
Definition: node_ref.hpp:50
detail::ProtoRing * ring_ptr() noexcept
Definition: assembler.hpp:485
bool empty() const noexcept
Definition: node_ref_list.hpp:61
bool debug() const noexcept
Definition: assembler.hpp:262
bool create_empty_areas
Definition: assembler.hpp:107
Definition: assembler.hpp:203
bool operator<(const rings_stack_element &rhs) const noexcept
Definition: assembler.hpp:493
std::vector< Location > m_split_locations
Definition: assembler.hpp:257
void rollback()
Definition: buffer.hpp:349
bool try_to_merge(open_ring_its_type &open_ring_its)
Definition: assembler.hpp:877
const NodeRef & back() const noexcept
Definition: node_ref_list.hpp:102
uint64_t area_simple_case
Simple case, no touching rings.
Definition: stats.hpp:51
uint64_t duplicate_nodes
Consecutive identical nodes or consecutive nodes with same location.
Definition: stats.hpp:53
detail::ProtoRing * find_enclosing_ring(detail::NodeRefSegment *segment)
Definition: assembler.hpp:511
constexpr int32_t y() const noexcept
Definition: location.hpp:332
uint32_t reverse
Definition: assembler.hpp:213
bool create_old_style_polygons
Definition: assembler.hpp:123
void add_tag(const char *key, const char *value)
Definition: osm_object_builder.hpp:81
uint64_t touching_rings
Rings touching in a node.
Definition: stats.hpp:68
OSMIUM_DEPRECATED void operator()(const osmium::Relation &relation, const std::vector< size_t > &members, const osmium::memory::Buffer &in_buffer, osmium::memory::Buffer &out_buffer)
Definition: assembler.hpp:1446
Definition: osm_object_builder.hpp:63
size_t commit()
Definition: buffer.hpp:335
Definition: osm_object_builder.hpp:376