342 const std::string &name,
351 std::vector<WaySegment> drivable;
352 std::map<long long, int> node_use;
359 segment.way_id = way.id;
361 segment.tags = way.tags;
362 segment.nodes = way.nodes;
365 for (std::size_t i = 0u; i < way.nodes.size(); ++i) {
366 const bool interior = (i > 0u) && (i + 1u < way.nodes.size());
367 node_use[way.nodes[i]] += interior ? 2 : 1;
369 drivable.push_back(std::move(segment));
373 std::set<long long> junction_nodes;
374 for (
const auto &entry : node_use) {
375 if (entry.second >= 3) {
376 junction_nodes.insert(entry.first);
380 auto node_point = [&](
long long id,
geom::Point &out) {
381 const auto it = osm.
nodes.find(
id);
382 if (it == osm.
nodes.end()) {
387 frame.
ToLocal(it->second.lon, it->second.lat,
x,
y);
395 std::map<long long, geom::Box> extent_of;
396 for (
long long node : junction_nodes) {
403 for (
const WaySegment &way : drivable) {
404 long long previous = 0;
405 bool have_previous =
false;
408 bool have_last =
false;
409 for (
long long node : way.nodes) {
419 if (junction_nodes.count(
node) == 0u) {
422 if (have_previous && chain <= options.
cluster_m) {
424 if (node_point(previous, previous_point) &&
428 const long long ra = clusters.Find(previous);
429 const long long rb = clusters.Find(
node);
432 geom::bg::expand(merged, extent_of[rb]);
433 const double width = merged.max_corner().x() - merged.min_corner().x();
434 const double height = merged.max_corner().y() - merged.min_corner().y();
435 if (std::max(width, height) <= options.
cluster_m * 0.75) {
436 clusters.Join(previous,
node);
437 extent_of[clusters.Find(previous)] = merged;
443 have_previous =
true;
449 std::map<long long, std::string> junction_of_node;
450 std::vector<JunctionLeg> legs;
451 std::map<std::string, PieceEnds> ends_of_road;
452 std::size_t road_index = 0u;
454 auto project = [&](
long long node_id,
geom::Point3 &out) {
455 const auto it = osm.
nodes.find(node_id);
456 if (it == osm.
nodes.end()) {
461 frame.
ToLocal(it->second.lon, it->second.lat,
x,
y);
466 for (
const WaySegment &way : drivable) {
470 std::vector<std::vector<long long>> pieces;
471 std::vector<long long> current;
472 long long open_cluster = 0;
473 bool inside_cluster =
false;
474 for (std::size_t i = 0u; i < way.nodes.size(); ++i) {
475 const long long node = way.nodes[i];
476 const bool is_junction = junction_nodes.count(
node) != 0u;
477 const long long cluster = is_junction ? clusters.Find(
node) : 0;
479 if (is_junction && (!inside_cluster || cluster != open_cluster)) {
481 current.push_back(
node);
482 if (current.size() >= 2u) {
483 pieces.push_back(current);
486 current.push_back(
node);
487 open_cluster = cluster;
488 inside_cluster =
true;
491 if (is_junction && inside_cluster && cluster == open_cluster) {
495 current.push_back(
node);
498 inside_cluster =
false;
499 current.push_back(
node);
501 if (current.size() >= 2u) {
502 pieces.push_back(current);
506 for (
const std::vector<long long> &piece : pieces) {
508 road.
id = MakeId(
"road_", road_index++);
509 road.highway = way.highway;
510 road.osm_way_ids.push_back(way.way_id);
511 road.tags = way.tags;
512 const std::string *way_name =
FindTag(way.tags,
"name");
513 if (way_name !=
nullptr) {
514 road.name = *way_name;
516 for (
long long node : piece) {
522 if (
road.reference_line.size() < 2u ||
527 FillLanes(
road, profile);
530 const long long first_node = piece.front();
531 const long long last_node = piece.back();
532 const bool start_on_junction = junction_nodes.count(first_node) != 0u;
533 const bool end_on_junction = junction_nodes.count(last_node) != 0u;
535 if (start_on_junction) {
538 if (end_on_junction) {
544 if (start_on_junction) {
546 leg.road_id =
road.id;
548 leg.point = flat.front();
550 leg.node = first_node;
552 junction_of_node.emplace(first_node, std::string());
554 if (end_on_junction) {
556 leg.road_id =
road.id;
558 leg.point = flat.back();
560 leg.node = last_node;
562 junction_of_node.emplace(last_node, std::string());
564 ends_of_road[
road.id] = PieceEnds{first_node, last_node};
573 std::map<long long, std::vector<std::string>> at_node;
574 for (
const auto &entry : ends_of_road) {
575 at_node[entry.second.first].push_back(entry.first);
576 if (entry.second.last != entry.second.first) {
577 at_node[entry.second.last].push_back(entry.first);
580 bool merged_any =
true;
583 for (
const auto &entry : at_node) {
584 const long long node = entry.first;
585 if (junction_nodes.count(
node) != 0u || entry.second.size() != 2u) {
591 if (
road.junction_id.has_value())
continue;
592 if (
road.id == entry.second[0]) a = &
road;
593 if (
road.id == entry.second[1]) b = &
road;
595 if (a ==
nullptr || b ==
nullptr || a == b) {
604 bool same_layout =
true;
605 for (std::size_t k = 0u; k < a->
lanes.size(); ++k) {
607 std::abs(a->
lanes[k].width - b->
lanes[k].width) > 0.01) {
615 PieceEnds &ea = ends_of_road[a->
id];
616 PieceEnds &eb = ends_of_road[b->
id];
618 auto flip_legs = [&legs](
const std::string &
road_id) {
619 for (JunctionLeg &leg : legs) {
626 if (ea.first ==
node) {
628 std::swap(ea.first, ea.last);
631 if (eb.last ==
node) {
633 std::swap(eb.first, eb.last);
636 if (ea.last !=
node || eb.first !=
node) {
643 for (
auto &list : at_node) {
644 for (std::string &
id : list.second) {
650 const std::string dead = b->
id;
652 for (JunctionLeg &leg : legs) {
653 if (leg.road_id == dead) {
658 ends_of_road.erase(dead);
659 model.
roads.erase(std::remove_if(model.
roads.begin(), model.
roads.end(),
660 [&dead](
const Road &r) { return r.id == dead; }), model.
roads.end());
672 const double internal_limit = 2.0 * options.
cluster_m;
673 std::map<std::string, std::vector<std::size_t>> legs_of_road;
674 for (std::size_t i = 0u; i < legs.size(); ++i) {
675 legs_of_road[legs[i].road_id].push_back(i);
677 std::set<std::string> internal;
678 for (
const auto &entry : legs_of_road) {
679 if (entry.second.size() < 2u) {
682 const long long root = clusters.Find(legs[entry.second.front()].node);
684 for (std::size_t i : entry.second) {
685 same = same && (clusters.Find(legs[i].
node) == root);
691 if (
road !=
nullptr && LineLength(
road->reference_line) <= internal_limit) {
692 internal.insert(entry.first);
695 if (!internal.empty()) {
696 model.
roads.erase(std::remove_if(model.
roads.begin(), model.
roads.end(),
697 [&internal](
const Road &r) {
return internal.count(r.id) != 0u; }),
699 std::vector<JunctionLeg> surviving;
700 for (JunctionLeg &leg : legs) {
701 if (internal.count(leg.road_id) == 0u) {
702 surviving.push_back(leg);
705 legs = std::move(surviving);
709 std::map<long long, std::vector<std::size_t>> legs_of_node;
710 for (std::size_t i = 0u; i < legs.size(); ++i) {
711 legs_of_node[clusters.Find(legs[i].
node)].push_back(i);
714 std::size_t junction_index = 0u;
715 std::vector<Road> connecting_roads;
716 for (
const auto &entry : legs_of_node) {
717 if (entry.second.size() < 3u) {
719 if (entry.second.size() == 2u) {
720 JunctionLeg &a = legs[entry.second[0]];
721 JunctionLeg &b = legs[entry.second[1]];
722 Road *road_a =
nullptr;
723 Road *road_b =
nullptr;
725 if (
road.id == a.road_id) road_a = &
road;
726 if (
road.id == b.road_id) road_b = &
road;
728 if (road_a !=
nullptr && road_b !=
nullptr) {
735 const bool mirrored = (a.contact == b.contact);
737 const int target = mirrored ? -lane.id : lane.id;
739 for (
const Lane &other : road_b->
lanes) {
740 exists = exists || (other.id == target);
746 : lane.successor_lane) = target;
749 const int target = mirrored ? -lane.id : lane.id;
751 for (
const Lane &other : road_a->
lanes) {
752 exists = exists || (other.id == target);
758 : lane.successor_lane) = target;
766 junction.
id = MakeId(
"junction_", junction_index++);
769 std::map<std::tuple<std::string, ContactPoint, std::string, ContactPoint>,
770 std::pair<std::string, double>> best_movement;
771 for (
long long node : junction_nodes) {
772 if (clusters.Find(
node) == entry.first) {
777 for (std::size_t i : entry.second) {
778 for (std::size_t j : entry.second) {
782 const JunctionLeg &in = legs[i];
783 const JunctionLeg &out = legs[j];
788 if (turn < (M_PI - options.
uturn_deg * M_PI / 180.0)) {
793 if (road_in ==
nullptr || road_out ==
nullptr) {
796 std::vector<int> arriving;
797 std::vector<int> leaving;
798 std::vector<int> ignored;
799 SplitLanesAtContact(*road_in, in.contact, arriving, ignored);
801 SplitLanesAtContact(*road_out, out.contact, ignored, leaving);
802 if (arriving.empty() || leaving.empty()) {
807 connecting.
id = MakeId(
"road_", road_index++);
812 out.point, out.heading,
815 const std::size_t width = std::min(arriving.size(), leaving.size());
816 for (std::size_t k = 0u; k < width; ++k) {
818 lane.
id = -
static_cast<int>(k) - 1;
820 lane.
width = road_in->
lanes.empty() ? 3.5 : road_in->
lanes.front().width;
824 connecting.
lanes.push_back(lane);
831 const std::tuple<std::string, ContactPoint, std::string, ContactPoint> movement{
832 in.road_id, in.contact, out.road_id, out.contact};
834 const auto seen = best_movement.find(movement);
835 if (seen != best_movement.end()) {
836 if (seen->second.second <= length) {
840 const std::string superseded = seen->second.first;
841 connecting_roads.erase(
842 std::remove_if(connecting_roads.begin(), connecting_roads.end(),
843 [&superseded](
const Road &r) { return r.id == superseded; }),
844 connecting_roads.end());
848 return c.connecting_road == superseded;
852 best_movement[movement] = std::make_pair(connecting.
id, length);
855 connection.
id = MakeId(
"connection_",
junction.connections.size());
859 for (std::size_t k = 0u; k < width; ++k) {
862 junction.connections.push_back(std::move(connection));
863 connecting_roads.push_back(std::move(connecting));
867 for (std::size_t i : entry.second) {
869 if (
road.id != legs[i].road_id) {
874 road.predecessor = link;
876 road.successor = link;
883 for (
Road &
road : connecting_roads) {
887 if (options.
clip.has_value()) {
888 ClipToBox(model, *options.
clip);