1 #ifndef OSMIUM_AREA_ASSEMBLER_HPP 2 #define OSMIUM_AREA_ASSEMBLER_HPP 47 #include <unordered_map> 48 #include <unordered_set> 67 #include <osmium/area/detail/proto_ring.hpp> 68 #include <osmium/area/detail/node_ref_segment.hpp> 69 #include <osmium/area/detail/segment_list.hpp> 153 problem_reporter(pr),
171 using open_ring_its_type = std::list<std::list<detail::ProtoRing>::iterator>;
173 struct location_to_ring_map {
175 open_ring_its_type::iterator ring_it;
178 location_to_ring_map(
const osmium::Location& l,
const open_ring_its_type::iterator& r,
bool s) noexcept :
190 const detail::ProtoRing& ring()
const noexcept {
196 inline bool operator==(
const location_to_ring_map& lhs,
const location_to_ring_map& rhs) noexcept {
197 return lhs.location == rhs.location;
200 inline bool operator<(
const location_to_ring_map& lhs,
const location_to_ring_map& rhs) noexcept {
201 return lhs.location < rhs.location;
217 static constexpr
const uint32_t invalid_item = 1 << 30;
227 explicit slocation(uint32_t n,
bool r =
false) noexcept :
233 const auto& segment = segment_list[item];
234 return reverse ? segment.second().location() : segment.first().location();
238 const auto& segment = segment_list[item];
239 return reverse ? segment.second() : segment.first();
243 if (item == invalid_item) {
244 return default_location;
246 return location(segment_list);
270 size_t m_num_members = 0;
295 std::map<std::string, size_t> counter;
297 for (
const auto& tag : way->tags()) {
298 std::string kv {tag.key()};
300 kv.append(tag.value());
305 const size_t num_ways = ways.size();
306 for (
const auto& t_c : counter) {
308 std::cerr <<
" tag " << t_c.first <<
" is used " << t_c.second <<
" times in " << num_ways <<
" ways\n";
310 if (t_c.second == num_ways) {
311 const size_t len = std::strlen(t_c.first.c_str());
312 tl_builder.
add_tag(t_c.first.c_str(), t_c.first.c_str() + len + 1);
321 add(
false,
"created_by");
322 add(
false,
"source");
324 add(
false,
"test:id");
325 add(
false,
"test:section");
338 if (std::strcmp(tag.key(),
"type")) {
339 tl_builder.add_tag(tag.key(), tag.value());
345 const auto count = std::count_if(relation.
tags().
cbegin(), relation.
tags().
cend(), filter());
348 std::cerr <<
" found " << count <<
" tags on relation (without ignored ones)\n";
353 std::cerr <<
" use tags from relation\n";
359 copy_tags_without_type(builder, relation.
tags());
364 std::cerr <<
" use tags from outer ways\n";
366 std::set<const osmium::Way*> ways;
367 for (
const auto& ring : m_rings) {
368 if (ring.is_outer()) {
372 if (ways.size() == 1) {
374 std::cerr <<
" only one outer way\n";
376 builder.
add_item((*ways.cbegin())->tags());
379 std::cerr <<
" multiple outer ways, get common tags\n";
382 add_common_tags(tl_builder, ways);
387 template <
typename TBuilder>
389 TBuilder ring_builder{builder};
390 ring_builder.add_node_ref(ring.get_node_ref_start());
391 for (
const auto& segment : ring.segments()) {
392 ring_builder.add_node_ref(segment->stop());
401 for (
const detail::ProtoRing& ring : m_rings) {
402 if (ring.is_outer()) {
403 build_ring_from_proto_ring<osmium::builder::OuterRingBuilder>(builder, ring);
404 for (
const detail::ProtoRing* inner : ring.inner_rings()) {
405 build_ring_from_proto_ring<osmium::builder::InnerRingBuilder>(builder, *inner);
413 std::cerr <<
" Checking inner/outer roles\n";
416 std::unordered_map<const osmium::Way*, const detail::ProtoRing*> way_rings;
417 std::unordered_set<const osmium::Way*> ways_in_multiple_rings;
419 for (
const detail::ProtoRing& ring : m_rings) {
420 for (
const auto& segment : ring.segments()) {
421 assert(segment->way());
423 if (!segment->role_empty() && (ring.is_outer() ? !segment->role_outer() : !segment->role_inner())) {
426 std::cerr <<
" Segment " << *segment <<
" from way " << segment->way()->id() <<
" has role '" << segment->role_name()
427 <<
"', but should have role '" << (ring.is_outer() ?
"outer" :
"inner") <<
"'\n";
430 if (ring.is_outer()) {
438 auto& r = way_rings[segment->way()];
441 }
else if (r != &ring) {
442 ways_in_multiple_rings.insert(segment->way());
448 for (
const osmium::Way* way : ways_in_multiple_rings) {
451 std::cerr <<
" Way " << way->id() <<
" is in multiple rings\n";
461 auto it = std::lower_bound(m_locations.begin(), m_locations.end(),
slocation{}, [
this, &location](
const slocation& lhs,
const slocation& rhs) {
462 return lhs.
location(m_segment_list, location) < rhs.location(m_segment_list, location);
465 assert(it != m_locations.end());
466 if (m_segment_list[it->item].is_done()) {
469 assert(it != m_locations.end());
471 assert(!m_segment_list[it->item].is_done());
472 return &m_segment_list[it->item];
484 m_ring_ptr(ring_ptr) {
487 double y() const noexcept {
491 const detail::ProtoRing&
ring() const noexcept {
500 return m_ring_ptr == rhs.m_ring_ptr;
504 return m_y < rhs.m_y;
513 const auto it = std::adjacent_find(outer_rings.begin(), outer_rings.end());
514 if (it == outer_rings.end()) {
517 outer_rings.erase(it, std::next(it, 2));
523 std::cerr <<
" Looking for ring enclosing " << *segment <<
"\n";
526 const auto location = segment->first().location();
527 const auto end_location = segment->second().location();
529 while (segment->first().location() == location) {
530 if (segment == &m_segment_list.back()) {
539 while (segment >= &m_segment_list.front()) {
540 if (!segment->is_direction_done()) {
545 std::cerr <<
" Checking against " << *segment <<
"\n";
550 if (segment->first().location() == location) {
551 const int64_t ax = a.
x();
552 const int64_t bx = b.
x();
553 const int64_t lx = end_location.x();
554 const int64_t ay = a.
y();
555 const int64_t by = b.
y();
556 const int64_t ly = end_location.y();
557 const auto z = (bx - ax)*(ly - ay) - (by - ay)*(lx - ax);
559 std::cerr <<
" Segment XXXX z=" << z <<
"\n";
562 nesting += segment->is_reverse() ? -1 : 1;
564 std::cerr <<
" Segment is below (nesting=" << nesting <<
")\n";
566 if (segment->ring()->is_outer()) {
568 std::cerr <<
" Segment belongs to outer ring\n";
570 outer_rings.emplace_back(a.
y(), segment->ring());
573 }
else if (a.
x() <= location.x() && location.x() < b.
x()) {
575 std::cerr <<
" Is in x range\n";
578 const int64_t ax = a.
x();
579 const int64_t bx = b.
x();
580 const int64_t lx = location.x();
581 const int64_t ay = a.
y();
582 const int64_t by = b.
y();
583 const int64_t ly = location.y();
584 const auto z = (bx - ax)*(ly - ay) - (by - ay)*(lx - ax);
587 nesting += segment->is_reverse() ? -1 : 1;
589 std::cerr <<
" Segment is below (nesting=" << nesting <<
")\n";
591 if (segment->ring()->is_outer()) {
593 std::cerr <<
" Segment belongs to outer ring\n";
595 const double y = ay + (by - ay) * (lx - ax) / double(bx - ax);
596 outer_rings.emplace_back(y, segment->ring());
603 if (nesting % 2 == 0) {
605 std::cerr <<
" Decided that this is an outer ring\n";
610 std::cerr <<
" Decided that this is an inner ring\n";
612 assert(!outer_rings.empty());
614 std::sort(outer_rings.rbegin(), outer_rings.rend());
616 for (
const auto& o : outer_rings) {
617 std::cerr <<
" y=" << o.y() <<
" " << o.ring() <<
"\n";
621 remove_duplicates(outer_rings);
623 std::cerr <<
" after remove duplicates:\n";
624 for (
const auto& o : outer_rings) {
625 std::cerr <<
" y=" << o.y() <<
" " << o.ring() <<
"\n";
629 assert(!outer_rings.empty());
630 return outer_rings.front().ring_ptr();
635 return std::find(m_split_locations.cbegin(), m_split_locations.cend(), location) != m_split_locations.cend();
639 detail::NodeRefSegment* segment = &m_segment_list[node.
item];
640 assert(!segment->is_done());
643 std::cerr <<
" Starting new ring at location " << node.
location(m_segment_list) <<
" with segment " << *segment <<
"\n";
652 if (segment != &m_segment_list.front()) {
653 outer_ring = find_enclosing_ring(segment);
655 segment->mark_direction_done();
657 m_rings.emplace_back(segment);
658 detail::ProtoRing* ring = &m_rings.back();
661 std::cerr <<
" This is an inner ring. Outer ring is " << *outer_ring <<
"\n";
663 outer_ring->add_inner_ring(ring);
664 ring->set_outer_ring(outer_ring);
665 }
else if (debug()) {
666 std::cerr <<
" This is an outer ring\n";
673 while (first_location != last_location) {
675 detail::NodeRefSegment* next_segment = get_next_segment(last_location);
676 next_segment->mark_direction_done();
677 if (next_segment->start().location() != last_location) {
678 next_segment->reverse();
680 ring->add_segment_back(next_segment);
682 std::cerr <<
" Next segment is " << *next_segment <<
"\n";
684 last_location = next_segment->stop().location();
687 ring->fix_direction();
690 std::cerr <<
" Completed ring: " << *ring <<
"\n";
697 detail::NodeRefSegment* segment = &m_segment_list[node.
item];
698 assert(!segment->is_done());
701 std::cerr <<
" Starting new ring at location " << node.
location(m_segment_list) <<
" with segment " << *segment <<
"\n";
708 m_rings.emplace_back(segment);
709 detail::ProtoRing* ring = &m_rings.back();
715 while (first_location != last_location && !is_split_location(last_location)) {
717 detail::NodeRefSegment* next_segment = get_next_segment(last_location);
718 if (next_segment->start().location() != last_location) {
719 next_segment->reverse();
721 ring->add_segment_back(next_segment);
723 std::cerr <<
" Next segment is " << *next_segment <<
"\n";
725 last_location = next_segment->stop().location();
729 if (first_location == last_location) {
730 std::cerr <<
" Completed ring: " << *ring <<
"\n";
732 std::cerr <<
" Completed partial ring: " << *ring <<
"\n";
740 m_locations.reserve(m_segment_list.size() * 2);
742 for (uint32_t n = 0; n < m_segment_list.size(); ++n) {
743 m_locations.emplace_back(n,
false);
744 m_locations.emplace_back(n,
true);
747 std::stable_sort(m_locations.begin(), m_locations.end(), [
this](
const slocation& lhs,
const slocation& rhs) {
748 return lhs.
location(m_segment_list) < rhs.location(m_segment_list);
753 detail::ProtoRing*
outer_ring = find_enclosing_ring(ring->min_segment());
755 outer_ring->add_inner_ring(ring);
756 ring->set_outer_ring(outer_ring);
758 ring->fix_direction();
759 ring->mark_direction_done();
764 std::cerr <<
" Finding inner/outer rings\n";
766 std::vector<detail::ProtoRing*> rings;
767 rings.reserve(m_rings.size());
768 for (
auto& ring : m_rings) {
770 rings.push_back(&ring);
778 std::sort(rings.begin(), rings.end(), [](detail::ProtoRing* a, detail::ProtoRing* b) {
779 return a->min_segment() < b->min_segment();
782 rings.front()->fix_direction();
783 rings.front()->mark_direction_done();
785 std::cerr <<
" First ring is outer: " << *rings.front() <<
"\n";
787 for (
auto it = std::next(rings.begin()); it != rings.end(); ++it) {
789 std::cerr <<
" Checking (at min segment " << *((*it)->min_segment()) <<
") ring " << **it <<
"\n";
791 find_inner_outer_complex(*it);
793 std::cerr <<
" Ring is " << ((*it)->is_outer() ?
"OUTER: " :
"INNER: ") << **it <<
"\n";
805 for (
auto it = m_locations.cbegin(); it != m_locations.cend(); ++it) {
808 if (std::next(it) == m_locations.cend() || loc != std::next(it)->location(m_segment_list)) {
810 std::cerr <<
" Found open ring at " << nr <<
"\n";
813 const auto& segment = m_segment_list[it->item];
818 if (loc == previous_location && (m_split_locations.empty() || m_split_locations.back() != previous_location )) {
819 m_split_locations.push_back(previous_location);
822 if (it == m_locations.end()) {
826 previous_location = loc;
832 auto count_remaining = m_segment_list.size();
834 const detail::NodeRefSegment& segment = m_segment_list[sl.item];
835 if (!segment.is_done()) {
836 count_remaining -= add_new_ring(sl);
837 if (count_remaining == 0) {
845 std::vector<location_to_ring_map> xrings;
846 xrings.reserve(open_ring_its.size() * 2);
848 for (
auto it = open_ring_its.begin(); it != open_ring_its.end(); ++it) {
850 std::cerr <<
" Ring: " << **it <<
"\n";
852 xrings.emplace_back((*it)->get_node_ref_start().location(), it,
true);
853 xrings.emplace_back((*it)->get_node_ref_stop().location(), it,
false);
856 std::sort(xrings.begin(), xrings.end());
862 std::list<detail::ProtoRing>::iterator r1 = *m1.ring_it;
863 std::list<detail::ProtoRing>::iterator r2 = *m2.ring_it;
865 if (r1->get_node_ref_stop().location() == r2->get_node_ref_start().location()) {
866 r1->join_forward(*r2);
867 }
else if (r1->get_node_ref_stop().location() == r2->get_node_ref_stop().location()) {
868 r1->join_backward(*r2);
869 }
else if (r1->get_node_ref_start().location() == r2->get_node_ref_start().location()) {
871 r1->join_forward(*r2);
872 }
else if (r1->get_node_ref_start().location() == r2->get_node_ref_stop().location()) {
874 r1->join_backward(*r2);
879 open_ring_its.erase(std::find(open_ring_its.begin(), open_ring_its.end(), r2));
883 open_ring_its.erase(std::find(open_ring_its.begin(), open_ring_its.end(), r1));
888 if (open_ring_its.empty()) {
893 std::cerr <<
" Trying to merge " << open_ring_its.size() <<
" open rings\n";
896 std::vector<location_to_ring_map> xrings = create_location_to_ring_map(open_ring_its);
898 auto it = xrings.cbegin();
899 while (it != xrings.cend()) {
900 it = std::adjacent_find(it, xrings.cend());
901 if (it == xrings.cend()) {
904 auto after = std::next(it, 2);
905 if (after == xrings.cend() || after->location != it->location) {
907 std::cerr <<
" Merging two rings\n";
909 merge_two_rings(open_ring_its, *it, *std::next(it));
912 while (it != xrings.cend() && it->location == after->location) {
921 return std::any_of(m_rings.cbegin(), m_rings.cend(), [](
const detail::ProtoRing& ring){
922 return !ring.closed();
928 std::vector<std::pair<location_to_ring_map, bool>>
rings;
933 sum(ring.ring().sum()),
935 start_location(ring.ring().get_node_ref_start().location()),
936 stop_location(ring.ring().get_node_ref_stop().location()) {
937 rings.emplace_back(ring, reverse);
941 return start_location == stop_location;
946 void find_candidates(std::vector<candidate>& candidates, std::unordered_set<osmium::Location>& loc_done,
const std::vector<location_to_ring_map>& xrings,
candidate& cand) {
949 for (
const auto& ring : cand.
rings) {
950 std::cerr <<
" " << ring.first.ring() << (ring.second ?
" reverse" :
"") <<
"\n";
954 const auto connections =
make_range(std::equal_range(xrings.cbegin(),
958 assert(connections.begin() != connections.end());
960 assert(!cand.
rings.empty());
961 const detail::ProtoRing* ring_leading_here = &cand.
rings.back().first.ring();
963 const detail::ProtoRing& ring = m.ring();
965 if (&ring != ring_leading_here) {
967 std::cerr <<
" next possible connection: " << ring << (m.start ?
"" :
" reverse") <<
"\n";
972 c.
rings.emplace_back(m,
false);
973 c.stop_location = ring.get_node_ref_stop().location();
976 c.rings.emplace_back(m,
true);
977 c.stop_location = ring.get_node_ref_start().location();
982 std::cerr <<
" found candidate\n";
984 candidates.push_back(c);
985 }
else if (loc_done.count(c.stop_location) == 0) {
987 std::cerr <<
" recurse...\n";
989 loc_done.insert(c.stop_location);
990 find_candidates(candidates, loc_done, xrings, c);
991 loc_done.erase(c.stop_location);
993 std::cerr <<
" ...back\n";
995 }
else if (debug()) {
996 std::cerr <<
" loop found\n";
1011 assert(!open_ring_its.empty());
1014 std::cerr <<
" Trying to merge " << open_ring_its.size() <<
" open rings\n";
1017 std::vector<location_to_ring_map> xrings = create_location_to_ring_map(open_ring_its);
1020 return lhs.ring().min_segment() < rhs.ring().min_segment();
1023 find_inner_outer_complex();
1024 detail::ProtoRing*
outer_ring = find_enclosing_ring(ring_min->ring().min_segment());
1025 bool ring_min_is_outer = !outer_ring;
1027 std::cerr <<
" Open ring is " << (ring_min_is_outer ?
"outer" :
"inner") <<
" ring\n";
1029 for (
auto& ring : m_rings) {
1037 std::unordered_set<osmium::Location> loc_done;
1039 loc_done.insert(cand.stop_location);
1041 std::vector<candidate> candidates;
1042 find_candidates(candidates, loc_done, xrings, cand);
1044 if (candidates.empty()) {
1046 std::cerr <<
" Found no candidates\n";
1048 if (!open_ring_its.empty()) {
1051 for (
auto& it : open_ring_its) {
1061 std::cerr <<
" Found candidates:\n";
1062 for (
const auto& cand : candidates) {
1063 std::cerr <<
" sum=" << cand.sum <<
"\n";
1064 for (
const auto& ring : cand.rings) {
1065 std::cerr <<
" " << ring.first.ring() << (ring.second ?
" reverse" :
"") <<
"\n";
1071 const auto chosen_cand = ring_min_is_outer ?
1072 std::min_element(candidates.cbegin(), candidates.cend(), [](
const candidate& lhs,
const candidate& rhs) {
1073 return std::abs(lhs.
sum) < std::abs(rhs.sum);
1075 std::max_element(candidates.cbegin(), candidates.cend(), [](
const candidate& lhs,
const candidate& rhs) {
1076 return std::abs(lhs.
sum) < std::abs(rhs.sum);
1080 std::cerr <<
" Decided on: sum=" << chosen_cand->sum <<
"\n";
1081 for (
const auto& ring : chosen_cand->rings) {
1082 std::cerr <<
" " << ring.first.ring() << (ring.second ?
" reverse" :
"") <<
"\n";
1087 assert(chosen_cand->rings.size() > 1);
1088 const auto& first_ring = chosen_cand->rings.front().first;
1089 const detail::ProtoRing& remaining_ring = first_ring.ring();
1090 for (
auto it = std::next(chosen_cand->rings.begin()); it != chosen_cand->rings.end(); ++it) {
1091 merge_two_rings(open_ring_its, first_ring, it->first);
1095 std::cerr <<
" Merged to " << remaining_ring <<
"\n";
1103 auto count_remaining = m_segment_list.size();
1105 const auto locs =
make_range(std::equal_range(m_locations.begin(),
1109 return lhs.
location(m_segment_list, location) < rhs.location(m_segment_list, location);
1111 for (
auto& loc : locs) {
1112 if (!m_segment_list[loc.item].is_done()) {
1113 count_remaining -= add_new_ring_complex(loc);
1114 if (count_remaining == 0) {
1122 if (count_remaining > 0) {
1124 const detail::NodeRefSegment& segment = m_segment_list[sl.item];
1125 if (!segment.is_done()) {
1126 count_remaining -= add_new_ring_complex(sl);
1127 if (count_remaining == 0) {
1138 if (there_are_open_rings()) {
1142 for (
auto it = m_rings.begin(); it != m_rings.end(); ++it) {
1143 if (!it->closed()) {
1144 open_ring_its.push_back(it);
1148 while (!open_ring_its.empty()) {
1150 std::cerr <<
" There are " << open_ring_its.size() <<
" open rings\n";
1152 while (try_to_merge(open_ring_its));
1154 if (!open_ring_its.empty()) {
1156 std::cerr <<
" After joining obvious cases there are still " << open_ring_its.size() <<
" open rings\n";
1158 if (!join_connected_rings(open_ring_its)) {
1165 std::cerr <<
" Joined all open rings\n";
1171 find_inner_outer_complex();
1181 std::unordered_set<const osmium::Way*> ways_in_segments;
1183 for (
const auto& segment : m_segment_list) {
1184 ways_in_segments.insert(segment.way());
1187 return ways_in_segments.size() < m_num_members;
1194 m_stats.
nodes += m_segment_list.size();
1199 m_segment_list.sort();
1211 if (m_segment_list.empty()) {
1213 std::cerr <<
" No segments left\n";
1220 if (ways_were_lost()) {
1222 std::cerr <<
" Complete ways removed because of duplicate segments\n";
1228 std::cerr <<
"Sorted de-duplicated segment list:\n";
1229 for (
const auto& s : m_segment_list) {
1230 std::cerr <<
" " << s <<
"\n";
1240 timer_intersection.
stop();
1251 create_locations_list();
1252 timer_locations_list.
stop();
1259 if (!find_split_locations()) {
1266 if (!m_split_locations.empty()) {
1268 std::cerr <<
" Found split locations:\n";
1270 for (
const auto& location : m_split_locations) {
1272 auto it = std::lower_bound(m_locations.cbegin(), m_locations.cend(),
slocation{}, [
this, &location](
const slocation& lhs,
const slocation& rhs) {
1273 return lhs.
location(m_segment_list, location) < rhs.location(m_segment_list, location);
1275 assert(it != m_locations.cend());
1280 std::cerr <<
" " << location <<
"\n";
1291 if (m_split_locations.empty()) {
1293 std::cerr <<
" No split locations -> using simple algorithm\n";
1297 timer_simple_case.
start();
1298 create_rings_simple_case();
1299 timer_simple_case.
stop();
1302 std::cerr <<
" Found split locations -> using complex algorithm\n";
1306 timer_complex_case.
start();
1307 if (!create_rings_complex_case()) {
1310 timer_complex_case.
stop();
1317 check_inner_outer_roles();
1321 m_stats.
outer_rings = std::count_if(m_rings.cbegin(), m_rings.cend(), [](
const detail::ProtoRing& ring){
1322 return ring.is_outer();
1326 #ifdef OSMIUM_WITH_TIMER 1334 if (m_split_locations.empty()) {
1338 std::cout <<
" 0" <<
1343 # ifdef OSMIUM_AREA_CHECK_INNER_OUTER_ROLES 1344 ' ' << timer_roles.elapsed_microseconds() <<
1354 #ifdef OSMIUM_WITH_TIMER 1355 static bool print_header() {
1356 std::cout <<
"nodes outer_rings inner_rings sort dupl intersection locations split simple_case complex_case roles_check\n";
1360 static bool init_header() {
1361 static bool printed_print_header = print_header();
1362 return printed_print_header;
1368 builder.initialize_from_object(way);
1370 const bool area_okay = create_rings();
1372 add_tags_to_area(builder, way);
1375 add_rings_to_area(builder);
1378 if (report_ways()) {
1386 m_num_members = members.size();
1388 builder.initialize_from_object(relation);
1390 const bool area_okay = create_rings();
1392 add_tags_to_area(builder, relation);
1395 add_rings_to_area(builder);
1398 if (report_ways()) {
1414 #ifdef OSMIUM_WITH_TIMER 1456 std::cerr <<
"\nAssembling way " << way.
id() <<
" containing " << m_segment_list.size() <<
" nodes\n";
1461 if (create_area(out_buffer, way)) {
1468 std::cerr <<
"Done: " << m_stats <<
"\n";
1483 std::vector<const osmium::Way*> ways;
1484 for (
size_t offset : members) {
1486 ways.push_back(&way);
1488 operator()(relation, ways, out_buffer);
1496 assert(relation.
members().
size() >= members.size());
1516 std::cerr <<
"\nAssembling relation " << relation.
id() <<
" containing " << members.size() <<
" way members with " << m_segment_list.size() <<
" nodes\n";
1519 const size_t area_offset = out_buffer.
committed();
1523 if (create_area(out_buffer, relation, members)) {
1540 std::vector<const osmium::Way*> ways_that_should_be_areas;
1543 if (!std::strcmp(member.
role(),
"inner")) {
1552 if (!std::equal(way_fi_begin, way_fi_end, area_fi_begin) || d !=
std::distance(area_fi_begin, area_fi_end)) {
1553 ways_that_should_be_areas.push_back(&way);
1567 std::cerr <<
"Done: " << m_stats <<
"\n";
1571 for (
const osmium::Way* way : ways_that_should_be_areas) {
1573 assembler(*way, out_buffer);
1591 #endif // OSMIUM_AREA_ASSEMBLER_HPP area_stats m_stats
Definition: assembler.hpp:267
void operator()(const osmium::Relation &relation, const std::vector< const osmium::Way *> &members, osmium::memory::Buffer &out_buffer)
Definition: assembler.hpp:1495
WayNodeList & nodes()
Definition: way.hpp:89
detail::location_to_ring_map location_to_ring_map
Definition: assembler.hpp:213
osmium::area::ProblemReporter * problem_reporter
Definition: assembler.hpp:87
#define OSMIUM_DEPRECATED
Definition: compatibility.hpp:50
void add_item(const osmium::memory::Item &item)
Definition: builder.hpp:217
bool operator==(const rings_stack_element &rhs) const noexcept
Definition: assembler.hpp:499
const TagList & tags() const
Get the list of tags for this object.
Definition: object.hpp:325
const osmium::NodeRef & node_ref(const detail::SegmentList &segment_list) const noexcept
Definition: assembler.hpp:237
iterator_range< It > make_range(P &&p)
Definition: iterator.hpp:77
int64_t sum
Definition: assembler.hpp:927
RelationMemberList & members()
Definition: relation.hpp:185
virtual void report_way_in_multiple_rings(const osmium::Way &way)
Definition: problem_reporter.hpp:180
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
rings_stack_element(double y, detail::ProtoRing *ring_ptr)
Definition: assembler.hpp:482
virtual void report_duplicate_node(osmium::object_id_type node_id1, osmium::object_id_type node_id2, osmium::Location location)
Definition: problem_reporter.hpp:106
static void copy_tags_without_type(osmium::builder::AreaBuilder &builder, const osmium::TagList &tags)
Definition: assembler.hpp:335
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:172
constexpr bool operator==(const Box &lhs, const Box &rhs) noexcept
Definition: box.hpp:221
void operator()(const osmium::Way &way, osmium::memory::Buffer &out_buffer)
Definition: assembler.hpp:1425
Definition: relation.hpp:168
virtual void report_way(const osmium::Way &way)
Definition: problem_reporter.hpp:198
bool report_ways() const noexcept
Definition: assembler.hpp:276
AssemblerConfig() noexcept=default
void start()
Definition: timer.hpp:82
void add_rings_to_area(osmium::builder::AreaBuilder &builder) const
Definition: assembler.hpp:400
static const MPFilter & filter() noexcept
Definition: assembler.hpp:330
uint64_t no_way_in_mp_relation
Multipolygon relation with no way members.
Definition: stats.hpp:62
double m_y
Definition: assembler.hpp:477
Definition: assembler.hpp:82
const_iterator cbegin() const noexcept
Definition: collection.hpp:164
bool ways_were_lost()
Definition: assembler.hpp:1180
Definition: entity_bits.hpp:72
void add_tags_to_area(osmium::builder::AreaBuilder &builder, const osmium::Relation &relation)
Definition: assembler.hpp:344
size_type size() const noexcept
Definition: collection.hpp:152
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:932
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 create_rings_complex_case()
Definition: assembler.hpp:1101
bool is_closed() const
Definition: way.hpp:112
void remove_duplicates(rings_stack &outer_rings)
Definition: assembler.hpp:511
std::list< detail::ProtoRing > m_rings
Definition: assembler.hpp:258
osmium::Location stop_location
Definition: assembler.hpp:930
Definition: assembler.hpp:475
std::vector< location_to_ring_map > create_location_to_ring_map(open_ring_its_type &open_ring_its)
Definition: assembler.hpp:844
slocation() noexcept
Definition: assembler.hpp:222
bool create_way_polygons
Definition: assembler.hpp:137
bool closed() const noexcept
Definition: assembler.hpp:940
bool create_area(osmium::memory::Buffer &out_buffer, const osmium::Way &way)
Definition: assembler.hpp:1366
const AssemblerConfig & m_config
Definition: assembler.hpp:252
uint64_t short_ways
Number of ways with less than two nodes.
Definition: stats.hpp:66
const detail::ProtoRing & ring() const noexcept
Definition: assembler.hpp:491
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:162
uint64_t duplicate_segments
Segments duplicated (going back and forth)
Definition: stats.hpp:54
std::vector< slocation > m_locations
Definition: assembler.hpp:261
osmium::area::detail::SegmentList m_segment_list
Definition: assembler.hpp:255
constexpr osmium::object_id_type ref() const noexcept
Definition: node_ref.hpp:65
bool empty() const noexcept
Definition: node_ref_list.hpp:74
bool operator<(const Changeset &lhs, const Changeset &rhs)
Definition: changeset.hpp:447
Definition: relation.hpp:57
void find_inner_outer_complex()
Definition: assembler.hpp:762
bool check_roles
Definition: assembler.hpp:104
Namespace for everything in the Osmium library.
Definition: assembler.hpp:73
void check_inner_outer_roles()
Definition: assembler.hpp:411
uint32_t item
Definition: assembler.hpp:219
double y() const noexcept
Definition: assembler.hpp:487
bool is_split_location(const osmium::Location &location) const noexcept
Definition: assembler.hpp:634
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:215
uint64_t from_ways
Area created from way.
Definition: stats.hpp:56
OSMIUM_DEPRECATED void enable_debug_output(bool d=true)
Definition: assembler.hpp:163
const_iterator cend() const noexcept
Definition: collection.hpp:168
Definition: problem_reporter.hpp:60
bool create_new_style_polygons
Definition: assembler.hpp:122
slocation(uint32_t n, bool r=false) noexcept
Definition: assembler.hpp:227
bool join_connected_rings(open_ring_its_type &open_ring_its)
Definition: assembler.hpp:1010
bool empty() const noexcept
Definition: collection.hpp:143
void set_object(osmium::item_type object_type, osmium::object_id_type object_id) noexcept
Definition: problem_reporter.hpp:85
detail::NodeRefSegment * get_next_segment(const osmium::Location &location)
Definition: assembler.hpp:460
void create_rings_simple_case()
Definition: assembler.hpp:831
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:946
Definition: assembler.hpp:317
constexpr int32_t y() const noexcept
Definition: location.hpp:352
int64_t object_id_type
Type for OSM object (node, way, or relation) IDs.
Definition: types.hpp:45
const osmium::area::area_stats & stats() const noexcept
Definition: assembler.hpp:1581
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:861
std::vector< std::pair< location_to_ring_map, bool > > rings
Definition: assembler.hpp:928
void create_locations_list()
Definition: assembler.hpp:739
bool keep_type_tag
Definition: assembler.hpp:144
int debug_level
Definition: assembler.hpp:94
uint32_t add_new_ring(slocation &node)
Definition: assembler.hpp:638
void set_nodes(size_t nodes) noexcept
Definition: problem_reporter.hpp:90
bool operator<(const rings_stack_element &rhs) const noexcept
Definition: assembler.hpp:503
virtual void report_touching_ring(osmium::object_id_type node_id, osmium::Location location)
Definition: problem_reporter.hpp:116
osmium::Location start_location
Definition: assembler.hpp:929
osmium::Location location(const detail::SegmentList &segment_list, const osmium::Location &default_location) const noexcept
Definition: assembler.hpp:242
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:1411
Definition: location.hpp:266
std::vector< rings_stack_element > rings_stack
Definition: assembler.hpp:509
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:478
void stop()
Definition: timer.hpp:85
uint64_t inner_rings
Number of inner rings.
Definition: stats.hpp:57
Definition: assembler.hpp:926
void add_common_tags(osmium::builder::TagListBuilder &tl_builder, std::set< const osmium::Way *> &ways) const
Definition: assembler.hpp:294
virtual void report_ring_not_closed(const osmium::NodeRef &nr, const osmium::Way *way=nullptr)
Definition: problem_reporter.hpp:152
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:212
object_id_type id() const noexcept
Get ID of this object.
Definition: object.hpp:126
size_t committed() const noexcept
Definition: buffer.hpp:268
bool debug() const noexcept
Definition: assembler.hpp:272
bool ends_have_same_id() const
Definition: way.hpp:116
bool find_split_locations()
Definition: assembler.hpp:803
Definition: buffer.hpp:97
const char * role() const noexcept
Definition: relation.hpp:138
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:752
static void build_ring_from_proto_ring(osmium::builder::AreaBuilder &builder, const detail::ProtoRing &ring)
Definition: assembler.hpp:388
uint64_t nodes
Number of nodes in the area.
Definition: stats.hpp:63
osmium::Location location(const detail::SegmentList &segment_list) const noexcept
Definition: assembler.hpp:232
bool create_area(osmium::memory::Buffer &out_buffer, const osmium::Relation &relation, const std::vector< const osmium::Way *> &members)
Definition: assembler.hpp:1385
uint64_t single_way_in_mp_relation
Multipolygon relation containing a single way.
Definition: stats.hpp:67
bool create_rings()
Definition: assembler.hpp:1193
const NodeRef & front() const noexcept
Definition: node_ref_list.hpp:126
virtual void report_inner_with_same_tags(const osmium::Way &way)
Definition: problem_reporter.hpp:189
uint32_t add_new_ring_complex(slocation &node)
Definition: assembler.hpp:696
constexpr int32_t x() const noexcept
Definition: location.hpp:348
const NodeRef & back() const noexcept
Definition: node_ref_list.hpp:138
MPFilter()
Definition: assembler.hpp:319
Definition: node_ref.hpp:50
detail::ProtoRing * ring_ptr() noexcept
Definition: assembler.hpp:495
bool create_empty_areas
Definition: assembler.hpp:114
Definition: assembler.hpp:210
std::vector< Location > m_split_locations
Definition: assembler.hpp:264
void rollback()
Definition: buffer.hpp:379
T & get(const size_t offset) const
Definition: buffer.hpp:413
bool try_to_merge(open_ring_its_type &open_ring_its)
Definition: assembler.hpp:887
uint64_t area_simple_case
Simple case, no touching rings.
Definition: stats.hpp:51
bool there_are_open_rings() const noexcept
Definition: assembler.hpp:920
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:521
size_type size() const noexcept
Definition: node_ref_list.hpp:83
int64_t elapsed_microseconds() const
Definition: timer.hpp:88
uint32_t reverse
Definition: assembler.hpp:220
bool create_old_style_polygons
Definition: assembler.hpp:130
void add_tag(const char *key, const char *value)
Definition: osm_object_builder.hpp:95
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:1482
Definition: osm_object_builder.hpp:71
size_t commit()
Definition: buffer.hpp:363
void add_tags_to_area(osmium::builder::AreaBuilder &builder, const osmium::Way &way) const
Definition: assembler.hpp:290
Definition: osm_object_builder.hpp:528