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;
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;
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());
348 std::cerr <<
" found " << count <<
" tags on relation (without ignored ones)\n";
353 std::cerr <<
" use tags from relation\n";
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";
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 int32_t
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 int32_t y = int32_t(ay + (by - ay) * (lx - ax) / (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";
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()) {
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) {
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();
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);
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";
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()) {
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 auto& r1 = *m1.ring_it;
863 auto& 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);
880 open_ring_its.remove(r2);
883 open_ring_its.remove(r1);
888 if (open_ring_its.empty()) {
893 std::cerr <<
" Trying to merge " << open_ring_its.size() <<
" open rings\n";
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";
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);
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);
976 c.
rings.emplace_back(m,
true);
982 std::cerr <<
" found candidate\n";
984 candidates.push_back(c);
987 std::cerr <<
" recurse...\n";
992 std::cerr <<
" ...back\n";
994 }
else if (
debug()) {
995 std::cerr <<
" loop found\n";
1010 assert(!open_ring_its.empty());
1013 std::cerr <<
" Trying to merge " << open_ring_its.size() <<
" open rings\n";
1019 return lhs.ring().min_segment() < rhs.ring().min_segment();
1024 bool ring_min_is_outer = !outer_ring;
1026 std::cerr <<
" Open ring is " << (ring_min_is_outer ?
"outer" :
"inner") <<
" ring\n";
1028 for (
auto& ring : m_rings) {
1036 std::unordered_set<osmium::Location> loc_done;
1038 loc_done.insert(cand.stop_location);
1040 std::vector<candidate> candidates;
1043 if (candidates.empty()) {
1045 std::cerr <<
" Found no candidates\n";
1047 if (!open_ring_its.empty()) {
1050 for (
auto& it : open_ring_its) {
1060 std::cerr <<
" Found candidates:\n";
1061 for (
const auto& cand : candidates) {
1062 std::cerr <<
" sum=" << cand.sum <<
"\n";
1063 for (
const auto& ring : cand.rings) {
1064 std::cerr <<
" " << ring.first.ring() << (ring.second ?
" reverse" :
"") <<
"\n";
1070 const auto chosen_cand = ring_min_is_outer ?
1071 std::min_element(candidates.cbegin(), candidates.cend(), [](
const candidate& lhs,
const candidate& rhs) {
1072 return std::abs(lhs.
sum) < std::abs(rhs.sum);
1074 std::max_element(candidates.cbegin(), candidates.cend(), [](
const candidate& lhs,
const candidate& rhs) {
1075 return std::abs(lhs.
sum) < std::abs(rhs.sum);
1079 std::cerr <<
" Decided on: sum=" << chosen_cand->sum <<
"\n";
1080 for (
const auto& ring : chosen_cand->rings) {
1081 std::cerr <<
" " << ring.first.ring() << (ring.second ?
" reverse" :
"") <<
"\n";
1086 assert(chosen_cand->rings.size() > 1);
1087 const auto& first_ring = chosen_cand->rings.front().first;
1088 for (
auto it = chosen_cand->rings.begin() + 1; it != chosen_cand->rings.end(); ++it) {
1093 std::cerr <<
" Merged to " << first_ring.ring() <<
"\n";
1101 auto count_remaining = m_segment_list.size();
1103 const auto locs =
make_range(std::equal_range(m_locations.begin(),
1107 return lhs.
location(m_segment_list, location) < rhs.location(m_segment_list, location);
1109 for (
auto& loc : locs) {
1110 if (!m_segment_list[loc.item].is_done()) {
1112 if (count_remaining == 0) {
1120 if (count_remaining > 0) {
1122 const detail::NodeRefSegment& segment = m_segment_list[sl.item];
1123 if (!segment.is_done()) {
1125 if (count_remaining == 0) {
1140 for (
auto it = m_rings.begin(); it != m_rings.end(); ++it) {
1141 if (!it->closed()) {
1142 open_ring_its.push_back(it);
1146 while (!open_ring_its.empty()) {
1148 std::cerr <<
" There are " << open_ring_its.size() <<
" open rings\n";
1152 if (!open_ring_its.empty()) {
1154 std::cerr <<
" After joining obvious cases there are still " << open_ring_its.size() <<
" open rings\n";
1163 std::cerr <<
" Joined all open rings\n";
1179 std::unordered_set<const osmium::Way*> ways_in_segments;
1181 for (
const auto& segment : m_segment_list) {
1182 ways_in_segments.insert(segment.way());
1192 m_stats.
nodes += m_segment_list.size();
1197 m_segment_list.sort();
1209 if (m_segment_list.empty()) {
1211 std::cerr <<
" No segments left\n";
1220 std::cerr <<
" Complete ways removed because of duplicate segments\n";
1226 std::cerr <<
"Sorted de-duplicated segment list:\n";
1227 for (
const auto& s : m_segment_list) {
1228 std::cerr <<
" " << s <<
"\n";
1238 timer_intersection.
stop();
1250 timer_locations_list.
stop();
1264 if (!m_split_locations.empty()) {
1266 std::cerr <<
" Found split locations:\n";
1268 for (
const auto& location : m_split_locations) {
1270 auto it = std::lower_bound(m_locations.cbegin(), m_locations.cend(),
slocation{}, [
this, &location](
const slocation& lhs,
const slocation& rhs) {
1271 return lhs.
location(m_segment_list, location) < rhs.location(m_segment_list, location);
1273 assert(it != m_locations.cend());
1278 std::cerr <<
" " << location <<
"\n";
1289 if (m_split_locations.empty()) {
1291 std::cerr <<
" No split locations -> using simple algorithm\n";
1295 timer_simple_case.
start();
1297 timer_simple_case.
stop();
1300 std::cerr <<
" Found split locations -> using complex algorithm\n";
1304 timer_complex_case.
start();
1308 timer_complex_case.
stop();
1319 m_stats.
outer_rings = std::count_if(m_rings.cbegin(), m_rings.cend(), [](
const detail::ProtoRing& ring){
1320 return ring.is_outer();
1324 #ifdef OSMIUM_WITH_TIMER
1332 if (m_split_locations.empty()) {
1336 std::cout <<
" 0" <<
1341 # ifdef OSMIUM_AREA_CHECK_INNER_OUTER_ROLES
1342 ' ' << timer_roles.elapsed_microseconds() <<
1352 #ifdef OSMIUM_WITH_TIMER
1353 static bool print_header() {
1354 std::cout <<
"nodes outer_rings inner_rings sort dupl intersection locations split simple_case complex_case roles_check\n";
1358 static bool init_header() {
1359 static bool printed_print_header = print_header();
1360 return printed_print_header;
1366 builder.initialize_from_object(way);
1384 m_num_members = members.size();
1386 builder.initialize_from_object(relation);
1411 m_segment_list(config.debug_level > 1) {
1412 #ifdef OSMIUM_WITH_TIMER
1428 if (way.tags().has_tag(
"area",
"no")) {
1438 if (way.nodes().size() < 2) {
1443 if (!way.ends_have_same_id()) {
1454 std::cerr <<
"\nAssembling way " << way.id() <<
" containing " << m_segment_list.size() <<
" nodes\n";
1460 out_buffer.commit();
1462 out_buffer.rollback();
1466 std::cerr <<
"Done: " << m_stats <<
"\n";
1481 std::vector<const osmium::Way*> ways;
1482 for (
size_t offset : members) {
1484 ways.push_back(&way);
1494 assert(relation.
members().
size() >= members.size());
1514 std::cerr <<
"\nAssembling relation " << relation.
id() <<
" containing " << members.size() <<
" way members with " << m_segment_list.size() <<
" nodes\n";
1517 const size_t area_offset = out_buffer.
committed();
1538 std::vector<const osmium::Way*> ways_that_should_be_areas;
1541 if (!std::strcmp(member.
role(),
"inner")) {
1550 if (!std::equal(way_fi_begin, way_fi_end, area_fi_begin) || d !=
std::distance(area_fi_begin, area_fi_end)) {
1551 ways_that_should_be_areas.push_back(&way);
1565 std::cerr <<
"Done: " << m_stats <<
"\n";
1569 for (
const osmium::Way* way : ways_that_should_be_areas) {
1571 assembler(*way, out_buffer);
1589 #endif // OSMIUM_AREA_ASSEMBLER_HPP
area_stats m_stats
Definition: assembler.hpp:267
WayNodeList & nodes()
Definition: way.hpp:78
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:201
bool operator==(const rings_stack_element &rhs) const noexcept
Definition: assembler.hpp:499
const osmium::NodeRef & node_ref(const detail::SegmentList &segment_list) const noexcept
Definition: assembler.hpp:237
rings_stack_element(int32_t y, detail::ProtoRing *ring_ptr)
Definition: assembler.hpp:482
iterator_range< It > make_range(P &&p)
Definition: iterator.hpp:77
int64_t sum
Definition: assembler.hpp:927
RelationMemberList & members()
Definition: relation.hpp:176
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
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
void add_rings_to_area(osmium::builder::AreaBuilder &builder) const
Definition: assembler.hpp:400
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:1423
Definition: relation.hpp:163
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
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
void operator()(const osmium::Relation &relation, const std::vector< const osmium::Way * > &members, osmium::memory::Buffer &out_buffer)
Definition: assembler.hpp:1493
Definition: assembler.hpp:82
static constexpr const uint32_t invalid_item
Definition: assembler.hpp:217
const_iterator cbegin() const noexcept
Definition: collection.hpp:160
bool ways_were_lost()
Definition: assembler.hpp:1178
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:148
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
double distance(const osmium::geom::Coordinates &c1, const osmium::geom::Coordinates &c2)
Definition: haversine.hpp:64
bool create_rings_complex_case()
Definition: assembler.hpp:1099
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
void add_common_tags(osmium::builder::TagListBuilder &tl_builder, std::set< const osmium::Way * > &ways) const
Definition: assembler.hpp:294
Definition: assembler.hpp:475
bool create_area(osmium::memory::Buffer &out_buffer, const osmium::Relation &relation, const std::vector< const osmium::Way * > &members)
Definition: assembler.hpp:1383
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:1364
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
bool empty() const noexcept
Definition: node_ref_list.hpp:73
~Assembler() noexcept=default
bool operator<(const Changeset &lhs, const Changeset &rhs)
Definition: changeset.hpp:441
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
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:164
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:1009
bool empty() const noexcept
Definition: collection.hpp:139
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:1579
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
const TagList & tags() const
Get the list of tags for this object.
Definition: object.hpp:317
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
int32_t m_y
Definition: assembler.hpp:477
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
void add_tags_to_area(osmium::builder::AreaBuilder &builder, const osmium::Way &way) const
Definition: assembler.hpp:290
osmium::Location location(const detail::SegmentList &segment_list, const osmium::Location &default_location) const noexcept
Definition: assembler.hpp:242
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:1409
size_t m_num_members
Definition: assembler.hpp:270
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
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:118
size_t committed() const noexcept
Definition: buffer.hpp:259
bool debug() const noexcept
Definition: assembler.hpp:272
bool find_split_locations()
Definition: assembler.hpp:803
Definition: buffer.hpp:97
const char * role() const noexcept
Definition: relation.hpp:138
T & get(const size_t offset) const
Definition: buffer.hpp:404
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
int32_t y() const noexcept
Definition: assembler.hpp:487
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
uint64_t single_way_in_mp_relation
Multipolygon relation containing a single way.
Definition: stats.hpp:67
bool create_rings()
Definition: assembler.hpp:1191
bool is_closed() const
Definition: way.hpp:101
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
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:370
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
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:1480
Definition: osm_object_builder.hpp:71
size_t commit()
Definition: buffer.hpp:354
Definition: osm_object_builder.hpp:526