// necessary static util functions for stxxl's sorting static InternalExtractorEdge min_osm_value() { return InternalExtractorEdge(MIN_OSM_NODEID, MIN_OSM_NODEID, 0, WeightData(), false, false, false, false, true, TRAVEL_MODE_INACCESSIBLE, false, INVALID_LANE_DESCRIPTIONID, guidance::RoadClassificationData()); }
// necessary static util functions for stxxl's sorting static InternalExtractorEdge min_osm_value() { return InternalExtractorEdge(MIN_OSM_NODEID, MIN_OSM_NODEID, 0, WeightData(), false, // forward false, // backward false, // roundabout false, // circular true, // can be startpoint TRAVEL_MODE_INACCESSIBLE, false, INVALID_LANE_DESCRIPTIONID, guidance::RoadClassification()); }
/** warning: caller needs to take care of synchronization! */ void ExtractorCallbacks::wayFunction(ExtractionWay &parsed_way) { if((0 < parsed_way.speed) || (0 < parsed_way.duration)) { //Only true if the way is specified by the speed profile if(UINT_MAX == parsed_way.id){ DEBUG("found bogus way with id: " << parsed_way.id << " of size " << parsed_way.path.size()); return; } if(0 < parsed_way.duration) { //TODO: iterate all way segments and set duration corresponding to the length of each segment parsed_way.speed = parsed_way.duration/(parsed_way.path.size()-1); } if(FLT_EPSILON >= fabs(-1. - parsed_way.speed)){ DEBUG("found way with bogus speed, id: " << parsed_way.id); return; } //Get the unique identifier for the street name const StringMap::const_iterator string_map_iterator = stringMap->find(parsed_way.name); if(stringMap->end() == string_map_iterator) { parsed_way.nameID = externalMemory->nameVector.size(); externalMemory->nameVector.push_back(parsed_way.name); stringMap->insert(std::make_pair(parsed_way.name, parsed_way.nameID)); } else { parsed_way.nameID = string_map_iterator->second; } if(ExtractionWay::opposite == parsed_way.direction) { std::reverse( parsed_way.path.begin(), parsed_way.path.end() ); parsed_way.direction = ExtractionWay::oneway; } const bool split_bidirectional_edge = (parsed_way.backward_speed > 0) && (parsed_way.speed != parsed_way.backward_speed); for(std::vector< NodeID >::size_type n = 0; n < parsed_way.path.size()-1; ++n) { externalMemory->allEdges.push_back( InternalExtractorEdge(parsed_way.path[n], parsed_way.path[n+1], parsed_way.type, (split_bidirectional_edge ? ExtractionWay::oneway : parsed_way.direction), parsed_way.speed, parsed_way.nameID, parsed_way.roundabout, parsed_way.ignoreInGrid, (0 < parsed_way.duration), parsed_way.isAccessRestricted ) ); externalMemory->usedNodeIDs.push_back(parsed_way.path[n]); } externalMemory->usedNodeIDs.push_back(parsed_way.path.back()); //The following information is needed to identify start and end segments of restrictions externalMemory->wayStartEndVector.push_back(_WayIDStartAndEndEdge(parsed_way.id, parsed_way.path[0], parsed_way.path[1], parsed_way.path[parsed_way.path.size()-2], parsed_way.path.back())); if(split_bidirectional_edge) { //Only true if the way should be split std::reverse( parsed_way.path.begin(), parsed_way.path.end() ); for(std::vector< NodeID >::size_type n = 0; n < parsed_way.path.size()-1; ++n) { externalMemory->allEdges.push_back( InternalExtractorEdge(parsed_way.path[n], parsed_way.path[n+1], parsed_way.type, ExtractionWay::oneway, parsed_way.backward_speed, parsed_way.nameID, parsed_way.roundabout, parsed_way.ignoreInGrid, (0 < parsed_way.duration), parsed_way.isAccessRestricted, (ExtractionWay::oneway == parsed_way.direction) ) ); } externalMemory->wayStartEndVector.push_back(_WayIDStartAndEndEdge(parsed_way.id, parsed_way.path[0], parsed_way.path[1], parsed_way.path[parsed_way.path.size()-2], parsed_way.path.back())); } } }
/** * Takes the geometry contained in the ```input_way``` and the tags computed * by the lua profile inside ```parsed_way``` and computes all edge segments. * * Depending on the forward/backwards weights the edges are split into forward * and backward edges. * * warning: caller needs to take care of synchronization! */ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const ExtractionWay &parsed_way) { if (((0 >= parsed_way.forward_speed) || (TRAVEL_MODE_INACCESSIBLE == parsed_way.forward_travel_mode)) && ((0 >= parsed_way.backward_speed) || (TRAVEL_MODE_INACCESSIBLE == parsed_way.backward_travel_mode)) && (0 >= parsed_way.duration)) { // Only true if the way is specified by the speed profile return; } if (input_way.nodes().size() <= 1) { // safe-guard against broken data return; } if (std::numeric_limits<decltype(input_way.id())>::max() == input_way.id()) { util::SimpleLogger().Write(logDEBUG) << "found bogus way with id: " << input_way.id() << " of size " << input_way.nodes().size(); return; } InternalExtractorEdge::WeightData forward_weight_data; InternalExtractorEdge::WeightData backward_weight_data; if (0 < parsed_way.duration) { const unsigned num_edges = (input_way.nodes().size() - 1); // FIXME We devide by the numer of nodes here, but should rather consider // the length of each segment. We would eigther have to compute the length // of the whole way here (we can't: no node coordinates) or push that back // to the container and keep a reference to the way. forward_weight_data.duration = parsed_way.duration / num_edges; forward_weight_data.type = InternalExtractorEdge::WeightType::WAY_DURATION; backward_weight_data.duration = parsed_way.duration / num_edges; backward_weight_data.type = InternalExtractorEdge::WeightType::WAY_DURATION; } else { if (parsed_way.forward_speed > 0 && parsed_way.forward_travel_mode != TRAVEL_MODE_INACCESSIBLE) { forward_weight_data.speed = parsed_way.forward_speed; forward_weight_data.type = InternalExtractorEdge::WeightType::SPEED; } if (parsed_way.backward_speed > 0 && parsed_way.backward_travel_mode != TRAVEL_MODE_INACCESSIBLE) { backward_weight_data.speed = parsed_way.backward_speed; backward_weight_data.type = InternalExtractorEdge::WeightType::SPEED; } } if (forward_weight_data.type == InternalExtractorEdge::WeightType::INVALID && backward_weight_data.type == InternalExtractorEdge::WeightType::INVALID) { util::SimpleLogger().Write(logDEBUG) << "found way with bogus speed, id: " << input_way.id(); return; } // FIXME this need to be moved into the profiles const char *data = input_way.get_value_by_key("highway"); guidance::RoadClassificationData road_classification; if (data) { road_classification.road_class = guidance::functionalRoadClassFromTag(data); } const auto laneStringToDescription = [](std::string lane_string) -> TurnLaneDescription { if (lane_string.empty()) return {}; TurnLaneDescription lane_description; typedef boost::tokenizer<boost::char_separator<char>> tokenizer; boost::char_separator<char> sep("|", "", boost::keep_empty_tokens); boost::char_separator<char> inner_sep(";", ""); tokenizer tokens(lane_string, sep); const constexpr std::size_t num_osm_tags = 11; const constexpr char *osm_lane_strings[num_osm_tags] = {"none", "through", "sharp_left", "left", "slight_left", "slight_right", "right", "sharp_right", "reverse", "merge_to_left", "merge_to_right"}; const constexpr TurnLaneType::Mask masks_by_osm_string[num_osm_tags + 1] = { TurnLaneType::none, TurnLaneType::straight, TurnLaneType::sharp_left, TurnLaneType::left, TurnLaneType::slight_left, TurnLaneType::slight_right, TurnLaneType::right, TurnLaneType::sharp_right, TurnLaneType::uturn, TurnLaneType::merge_to_left, TurnLaneType::merge_to_right, TurnLaneType::empty}; // fallback, if string not found for (auto iter = tokens.begin(); iter != tokens.end(); ++iter) { tokenizer inner_tokens(*iter, inner_sep); guidance::TurnLaneType::Mask lane_mask = inner_tokens.begin() == inner_tokens.end() ? TurnLaneType::none : TurnLaneType::empty; for (auto token_itr = inner_tokens.begin(); token_itr != inner_tokens.end(); ++token_itr) { auto position = std::find(osm_lane_strings, osm_lane_strings + num_osm_tags, *token_itr); const auto translated_mask = masks_by_osm_string[std::distance(osm_lane_strings, position)]; if (translated_mask == TurnLaneType::empty) { // if we have unsupported tags, don't handle them util::SimpleLogger().Write(logDEBUG) << "Unsupported lane tag found: \"" << *token_itr << "\""; return {}; } BOOST_ASSERT((lane_mask & translated_mask) == 0); // make sure the mask is valid lane_mask |= translated_mask; } // add the lane to the description lane_description.push_back(lane_mask); } return lane_description; }; // convert the lane description into an ID and, if necessary, remembr the description in the // description_map const auto requestId = [&](std::string lane_string) { if (lane_string.empty()) return INVALID_LANE_DESCRIPTIONID; TurnLaneDescription lane_description = laneStringToDescription(std::move(lane_string)); const auto lane_description_itr = lane_description_map.find(lane_description); if (lane_description_itr == lane_description_map.end()) { const LaneDescriptionID new_id = boost::numeric_cast<LaneDescriptionID>(lane_description_map.size()); lane_description_map[lane_description] = new_id; // since we are getting a new ID, we can augment the current offsets // and store the turn lane masks, sadly stxxl does not support insert for (const auto mask : lane_description) external_memory.turn_lane_masks.push_back(mask); external_memory.turn_lane_offsets.push_back(external_memory.turn_lane_offsets.back() + lane_description.size()); return new_id; } else { return lane_description_itr->second; } }; // Deduplicates street names and street destination names based on the street_map map. // In case we do not already store the name, inserts (name, id) tuple and return id. // Otherwise fetches the id based on the name and returns it without insertion. const auto turn_lane_id_forward = requestId(parsed_way.turn_lanes_forward); const auto turn_lane_id_backward = requestId(parsed_way.turn_lanes_backward); const constexpr auto MAX_STRING_LENGTH = 255u; // Get the unique identifier for the street name // Get the unique identifier for the street name and destination const auto name_iterator = string_map.find(MapKey(parsed_way.name, parsed_way.destinations)); unsigned name_id = EMPTY_NAMEID; if (string_map.end() == name_iterator) { const auto name_length = std::min<unsigned>(MAX_STRING_LENGTH, parsed_way.name.size()); const auto destinations_length = std::min<unsigned>(MAX_STRING_LENGTH, parsed_way.destinations.size()); const auto pronunciation_length = std::min<unsigned>(MAX_STRING_LENGTH, parsed_way.pronunciation.size()); // name_offsets already has an offset of a new name, take the offset index as the name id name_id = external_memory.name_offsets.size() - 1; external_memory.name_char_data.reserve(external_memory.name_char_data.size() + name_length + destinations_length + pronunciation_length); std::copy(parsed_way.name.c_str(), parsed_way.name.c_str() + name_length, std::back_inserter(external_memory.name_char_data)); external_memory.name_offsets.push_back(external_memory.name_char_data.size()); std::copy(parsed_way.destinations.c_str(), parsed_way.destinations.c_str() + destinations_length, std::back_inserter(external_memory.name_char_data)); external_memory.name_offsets.push_back(external_memory.name_char_data.size()); std::copy(parsed_way.pronunciation.c_str(), parsed_way.pronunciation.c_str() + pronunciation_length, std::back_inserter(external_memory.name_char_data)); external_memory.name_offsets.push_back(external_memory.name_char_data.size()); auto k = MapKey{parsed_way.name, parsed_way.destinations}; auto v = MapVal{name_id}; string_map.emplace(std::move(k), std::move(v)); } else { name_id = name_iterator->second; } const bool split_edge = (parsed_way.forward_speed > 0) && (TRAVEL_MODE_INACCESSIBLE != parsed_way.forward_travel_mode) && (parsed_way.backward_speed > 0) && (TRAVEL_MODE_INACCESSIBLE != parsed_way.backward_travel_mode) && ((parsed_way.forward_speed != parsed_way.backward_speed) || (parsed_way.forward_travel_mode != parsed_way.backward_travel_mode) || (turn_lane_id_forward != turn_lane_id_backward)); external_memory.used_node_id_list.reserve(external_memory.used_node_id_list.size() + input_way.nodes().size()); std::transform(input_way.nodes().begin(), input_way.nodes().end(), std::back_inserter(external_memory.used_node_id_list), [](const osmium::NodeRef &ref) { return OSMNodeID{static_cast<std::uint64_t>(ref.ref())}; }); const bool is_opposite_way = TRAVEL_MODE_INACCESSIBLE == parsed_way.forward_travel_mode; // traverse way in reverse in this case if (is_opposite_way) { BOOST_ASSERT(split_edge == false); BOOST_ASSERT(parsed_way.backward_travel_mode != TRAVEL_MODE_INACCESSIBLE); util::for_each_pair( input_way.nodes().crbegin(), input_way.nodes().crend(), [&](const osmium::NodeRef &first_node, const osmium::NodeRef &last_node) { external_memory.all_edges_list.push_back( InternalExtractorEdge(OSMNodeID{static_cast<std::uint64_t>(first_node.ref())}, OSMNodeID{static_cast<std::uint64_t>(last_node.ref())}, name_id, backward_weight_data, true, false, parsed_way.roundabout, parsed_way.is_access_restricted, parsed_way.is_startpoint, parsed_way.backward_travel_mode, false, turn_lane_id_backward, road_classification)); }); external_memory.way_start_end_id_list.push_back( {OSMWayID{static_cast<std::uint32_t>(input_way.id())}, OSMNodeID{static_cast<std::uint64_t>(input_way.nodes().back().ref())}, OSMNodeID{static_cast<std::uint64_t>(input_way.nodes()[input_way.nodes().size() - 2].ref())}, OSMNodeID{static_cast<std::uint64_t>(input_way.nodes()[1].ref())}, OSMNodeID{static_cast<std::uint64_t>(input_way.nodes()[0].ref())}}); } else { const bool forward_only = split_edge || TRAVEL_MODE_INACCESSIBLE == parsed_way.backward_travel_mode; util::for_each_pair( input_way.nodes().cbegin(), input_way.nodes().cend(), [&](const osmium::NodeRef &first_node, const osmium::NodeRef &last_node) { external_memory.all_edges_list.push_back( InternalExtractorEdge(OSMNodeID{static_cast<std::uint64_t>(first_node.ref())}, OSMNodeID{static_cast<std::uint64_t>(last_node.ref())}, name_id, forward_weight_data, true, !forward_only, parsed_way.roundabout, parsed_way.is_access_restricted, parsed_way.is_startpoint, parsed_way.forward_travel_mode, split_edge, turn_lane_id_forward, road_classification)); }); if (split_edge) { BOOST_ASSERT(parsed_way.backward_travel_mode != TRAVEL_MODE_INACCESSIBLE); util::for_each_pair( input_way.nodes().cbegin(), input_way.nodes().cend(), [&](const osmium::NodeRef &first_node, const osmium::NodeRef &last_node) { external_memory.all_edges_list.push_back( InternalExtractorEdge(OSMNodeID{static_cast<std::uint64_t>(first_node.ref())}, OSMNodeID{static_cast<std::uint64_t>(last_node.ref())}, name_id, backward_weight_data, false, true, parsed_way.roundabout, parsed_way.is_access_restricted, parsed_way.is_startpoint, parsed_way.backward_travel_mode, true, turn_lane_id_backward, road_classification)); }); } external_memory.way_start_end_id_list.push_back( {OSMWayID{static_cast<std::uint32_t>(input_way.id())}, OSMNodeID{static_cast<std::uint64_t>(input_way.nodes().back().ref())}, OSMNodeID{static_cast<std::uint64_t>(input_way.nodes()[input_way.nodes().size() - 2].ref())}, OSMNodeID{static_cast<std::uint64_t>(input_way.nodes()[1].ref())}, OSMNodeID{static_cast<std::uint64_t>(input_way.nodes()[0].ref())}}); } }
static InternalExtractorEdge max_value() { return InternalExtractorEdge(SPECIAL_NODEID, SPECIAL_NODEID, 0, 0, 0, false, false, false, false, TRAVEL_MODE_INACCESSIBLE, false); }
// necessary static util functions for stxxl's sorting static InternalExtractorEdge min_value() { return InternalExtractorEdge(0, 0, 0, 0, 0, false, false, false, false, TRAVEL_MODE_INACCESSIBLE, false); }
/** warning: caller needs to take care of synchronization! */ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const ExtractionWay &parsed_way) { if (((0 >= parsed_way.forward_speed) || (TRAVEL_MODE_INACCESSIBLE == parsed_way.forward_travel_mode)) && ((0 >= parsed_way.backward_speed) || (TRAVEL_MODE_INACCESSIBLE == parsed_way.backward_travel_mode)) && (0 >= parsed_way.duration)) { // Only true if the way is specified by the speed profile return; } if (input_way.nodes().size() <= 1) { // safe-guard against broken data return; } if (std::numeric_limits<decltype(input_way.id())>::max() == input_way.id()) { SimpleLogger().Write(logDEBUG) << "found bogus way with id: " << input_way.id() << " of size " << input_way.nodes().size(); return; } if (0 < parsed_way.duration) { // TODO: iterate all way segments and set duration corresponding to the length of each // segment const_cast<ExtractionWay &>(parsed_way).forward_speed = parsed_way.duration / (input_way.nodes().size() - 1); const_cast<ExtractionWay &>(parsed_way).backward_speed = parsed_way.duration / (input_way.nodes().size() - 1); } if (std::numeric_limits<double>::epsilon() >= std::abs(-1. - parsed_way.forward_speed)) { SimpleLogger().Write(logDEBUG) << "found way with bogus speed, id: " << input_way.id(); return; } // Get the unique identifier for the street name const auto &string_map_iterator = string_map.find(parsed_way.name); unsigned name_id = external_memory.name_list.size(); if (string_map.end() == string_map_iterator) { external_memory.name_list.push_back(parsed_way.name); string_map.insert(std::make_pair(parsed_way.name, name_id)); } else { name_id = string_map_iterator->second; } const bool split_edge = (parsed_way.forward_speed > 0) && (TRAVEL_MODE_INACCESSIBLE != parsed_way.forward_travel_mode) && (parsed_way.backward_speed > 0) && (TRAVEL_MODE_INACCESSIBLE != parsed_way.backward_travel_mode) && ((parsed_way.forward_speed != parsed_way.backward_speed) || (parsed_way.forward_travel_mode != parsed_way.backward_travel_mode)); auto pair_wise_segment_split = [&](const osmium::NodeRef &first_node, const osmium::NodeRef &last_node) { // SimpleLogger().Write() << "adding edge (" << first_node.ref() << "," << // last_node.ref() << "), fwd speed: " << parsed_way.forward_speed; external_memory.all_edges_list.push_back(InternalExtractorEdge( (EdgeID)input_way.id(), first_node.ref(), last_node.ref(), ((split_edge || TRAVEL_MODE_INACCESSIBLE == parsed_way.backward_travel_mode) ? ExtractionWay::oneway : ExtractionWay::bidirectional), parsed_way.forward_speed, name_id, parsed_way.roundabout, parsed_way.ignore_in_grid, (0 < parsed_way.duration), parsed_way.is_access_restricted, parsed_way.forward_travel_mode, split_edge)); external_memory.used_node_id_list.push_back(first_node.ref()); }; const bool is_opposite_way = TRAVEL_MODE_INACCESSIBLE == parsed_way.forward_travel_mode; if (is_opposite_way) { const_cast<ExtractionWay &>(parsed_way).forward_travel_mode = parsed_way.backward_travel_mode; const_cast<ExtractionWay &>(parsed_way).backward_travel_mode = TRAVEL_MODE_INACCESSIBLE; osrm::for_each_pair(input_way.nodes().crbegin(), input_way.nodes().crend(), pair_wise_segment_split); external_memory.used_node_id_list.push_back(input_way.nodes().front().ref()); } else { osrm::for_each_pair(input_way.nodes().cbegin(), input_way.nodes().cend(), pair_wise_segment_split); external_memory.used_node_id_list.push_back(input_way.nodes().back().ref()); } // The following information is needed to identify start and end segments of restrictions external_memory.way_start_end_id_list.push_back( {(EdgeID)input_way.id(), (NodeID)input_way.nodes()[0].ref(), (NodeID)input_way.nodes()[1].ref(), (NodeID)input_way.nodes()[input_way.nodes().size() - 2].ref(), (NodeID)input_way.nodes().back().ref()}); if (split_edge) { // Only true if the way should be split BOOST_ASSERT(parsed_way.backward_travel_mode > 0); auto pair_wise_segment_split_2 = [&](const osmium::NodeRef &first_node, const osmium::NodeRef &last_node) { // SimpleLogger().Write() << "adding edge (" << last_node.ref() << "," << // first_node.ref() << "), bwd speed: " << parsed_way.backward_speed; external_memory.all_edges_list.push_back(InternalExtractorEdge( (EdgeID)input_way.id(), last_node.ref(), first_node.ref(), ExtractionWay::oneway, parsed_way.backward_speed, name_id, parsed_way.roundabout, parsed_way.ignore_in_grid, (0 < parsed_way.duration), parsed_way.is_access_restricted, parsed_way.backward_travel_mode, split_edge)); }; if (is_opposite_way) { // SimpleLogger().Write() << "opposite2"; osrm::for_each_pair(input_way.nodes().crbegin(), input_way.nodes().crend(), pair_wise_segment_split_2); external_memory.used_node_id_list.push_back(input_way.nodes().front().ref()); } else { osrm::for_each_pair(input_way.nodes().cbegin(), input_way.nodes().cend(), pair_wise_segment_split_2); external_memory.used_node_id_list.push_back(input_way.nodes().back().ref()); } external_memory.way_start_end_id_list.push_back( {(EdgeID)input_way.id(), (NodeID)input_way.nodes()[1].ref(), (NodeID)input_way.nodes()[0].ref(), (NodeID)input_way.nodes().back().ref(), (NodeID)input_way.nodes()[input_way.nodes().size() - 2].ref()}); } }
/** * Takes the geometry contained in the ```input_way``` and the tags computed * by the lua profile inside ```parsed_way``` and computes all edge segments. * * Depending on the forward/backwards weights the edges are split into forward * and backward edges. * * warning: caller needs to take care of synchronization! */ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const ExtractionWay &parsed_way) { if (((0 >= parsed_way.forward_speed) || (TRAVEL_MODE_INACCESSIBLE == parsed_way.forward_travel_mode)) && ((0 >= parsed_way.backward_speed) || (TRAVEL_MODE_INACCESSIBLE == parsed_way.backward_travel_mode)) && (0 >= parsed_way.duration)) { // Only true if the way is specified by the speed profile return; } if (input_way.nodes().size() <= 1) { // safe-guard against broken data return; } if (std::numeric_limits<decltype(input_way.id())>::max() == input_way.id()) { util::SimpleLogger().Write(logDEBUG) << "found bogus way with id: " << input_way.id() << " of size " << input_way.nodes().size(); return; } InternalExtractorEdge::WeightData forward_weight_data; InternalExtractorEdge::WeightData backward_weight_data; if (0 < parsed_way.duration) { const unsigned num_edges = (input_way.nodes().size() - 1); // FIXME We devide by the numer of nodes here, but should rather consider // the length of each segment. We would eigther have to compute the length // of the whole way here (we can't: no node coordinates) or push that back // to the container and keep a reference to the way. forward_weight_data.duration = parsed_way.duration / num_edges; forward_weight_data.type = InternalExtractorEdge::WeightType::WAY_DURATION; backward_weight_data.duration = parsed_way.duration / num_edges; backward_weight_data.type = InternalExtractorEdge::WeightType::WAY_DURATION; } else { if (parsed_way.forward_speed > 0 && parsed_way.forward_travel_mode != TRAVEL_MODE_INACCESSIBLE) { forward_weight_data.speed = parsed_way.forward_speed; forward_weight_data.type = InternalExtractorEdge::WeightType::SPEED; } if (parsed_way.backward_speed > 0 && parsed_way.backward_travel_mode != TRAVEL_MODE_INACCESSIBLE) { backward_weight_data.speed = parsed_way.backward_speed; backward_weight_data.type = InternalExtractorEdge::WeightType::SPEED; } } if (forward_weight_data.type == InternalExtractorEdge::WeightType::INVALID && backward_weight_data.type == InternalExtractorEdge::WeightType::INVALID) { util::SimpleLogger().Write(logDEBUG) << "found way with bogus speed, id: " << input_way.id(); return; } // FIXME this need to be moved into the profiles const char *data = input_way.get_value_by_key("highway"); guidance::RoadClassificationData road_classification; if (data) { road_classification.road_class = guidance::functionalRoadClassFromTag(data); } // Deduplicates street names and street destination names based on the street_map map. // In case we do not already store the name, inserts (name, id) tuple and return id. // Otherwise fetches the id based on the name and returns it without insertion. const constexpr auto MAX_STRING_LENGTH = 255u; // Get the unique identifier for the street name const auto string_map_iterator = string_map.find(parsed_way.name); unsigned name_id = external_memory.name_lengths.size(); if (string_map.end() == string_map_iterator) { auto name_length = std::min<unsigned>(MAX_STRING_LENGTH, parsed_way.name.size()); external_memory.name_char_data.reserve(name_id + name_length); std::copy(parsed_way.name.c_str(), parsed_way.name.c_str() + name_length, std::back_inserter(external_memory.name_char_data)); external_memory.name_lengths.push_back(name_length); string_map.insert(std::make_pair(parsed_way.name, name_id)); } else { name_id = string_map_iterator->second; } const bool split_edge = (parsed_way.forward_speed > 0) && (TRAVEL_MODE_INACCESSIBLE != parsed_way.forward_travel_mode) && (parsed_way.backward_speed > 0) && (TRAVEL_MODE_INACCESSIBLE != parsed_way.backward_travel_mode) && ((parsed_way.forward_speed != parsed_way.backward_speed) || (parsed_way.forward_travel_mode != parsed_way.backward_travel_mode)); std::transform(input_way.nodes().begin(), input_way.nodes().end(), std::back_inserter(external_memory.used_node_id_list), [](const osmium::NodeRef &ref) { return OSMNodeID(ref.ref()); }); const bool is_opposite_way = TRAVEL_MODE_INACCESSIBLE == parsed_way.forward_travel_mode; // traverse way in reverse in this case if (is_opposite_way) { BOOST_ASSERT(split_edge == false); BOOST_ASSERT(parsed_way.backward_travel_mode != TRAVEL_MODE_INACCESSIBLE); util::for_each_pair( input_way.nodes().crbegin(), input_way.nodes().crend(), [&](const osmium::NodeRef &first_node, const osmium::NodeRef &last_node) { external_memory.all_edges_list.push_back( InternalExtractorEdge(OSMNodeID(first_node.ref()), OSMNodeID(last_node.ref()), name_id, backward_weight_data, true, false, parsed_way.roundabout, parsed_way.is_access_restricted, parsed_way.is_startpoint, parsed_way.backward_travel_mode, false, road_classification)); }); external_memory.way_start_end_id_list.push_back( {OSMWayID(input_way.id()), OSMNodeID(input_way.nodes().back().ref()), OSMNodeID(input_way.nodes()[input_way.nodes().size() - 2].ref()), OSMNodeID(input_way.nodes()[1].ref()), OSMNodeID(input_way.nodes()[0].ref())}); } else { const bool forward_only = split_edge || TRAVEL_MODE_INACCESSIBLE == parsed_way.backward_travel_mode; util::for_each_pair( input_way.nodes().cbegin(), input_way.nodes().cend(), [&](const osmium::NodeRef &first_node, const osmium::NodeRef &last_node) { external_memory.all_edges_list.push_back( InternalExtractorEdge(OSMNodeID(first_node.ref()), OSMNodeID(last_node.ref()), name_id, forward_weight_data, true, !forward_only, parsed_way.roundabout, parsed_way.is_access_restricted, parsed_way.is_startpoint, parsed_way.forward_travel_mode, split_edge, road_classification)); }); if (split_edge) { BOOST_ASSERT(parsed_way.backward_travel_mode != TRAVEL_MODE_INACCESSIBLE); util::for_each_pair( input_way.nodes().cbegin(), input_way.nodes().cend(), [&](const osmium::NodeRef &first_node, const osmium::NodeRef &last_node) { external_memory.all_edges_list.push_back( InternalExtractorEdge(OSMNodeID(first_node.ref()), OSMNodeID(last_node.ref()), name_id, backward_weight_data, false, true, parsed_way.roundabout, parsed_way.is_access_restricted, parsed_way.is_startpoint, parsed_way.backward_travel_mode, true, road_classification)); }); } external_memory.way_start_end_id_list.push_back( {OSMWayID(input_way.id()), OSMNodeID(input_way.nodes().back().ref()), OSMNodeID(input_way.nodes()[input_way.nodes().size() - 2].ref()), OSMNodeID(input_way.nodes()[1].ref()), OSMNodeID(input_way.nodes()[0].ref())}); } }
/** * Takes the geometry contained in the ```input_way``` and the tags computed * by the lua profile inside ```parsed_way``` and computes all edge segments. * * Depending on the forward/backwards weights the edges are split into forward * and backward edges. * * warning: caller needs to take care of synchronization! */ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const ExtractionWay &parsed_way) { if (((0 >= parsed_way.forward_speed) || (TRAVEL_MODE_INACCESSIBLE == parsed_way.forward_travel_mode)) && ((0 >= parsed_way.backward_speed) || (TRAVEL_MODE_INACCESSIBLE == parsed_way.backward_travel_mode)) && (0 >= parsed_way.duration)) { // Only true if the way is specified by the speed profile return; } if (input_way.nodes().size() <= 1) { // safe-guard against broken data return; } if (std::numeric_limits<decltype(input_way.id())>::max() == input_way.id()) { SimpleLogger().Write(logDEBUG) << "found bogus way with id: " << input_way.id() << " of size " << input_way.nodes().size(); return; } InternalExtractorEdge::WeightData forward_weight_data; InternalExtractorEdge::WeightData backward_weight_data; if (0 < parsed_way.duration) { const unsigned num_edges = (input_way.nodes().size() - 1); // FIXME We devide by the numer of nodes here, but should rather consider // the length of each segment. We would eigther have to compute the length // of the whole way here (we can't: no node coordinates) or push that back // to the container and keep a reference to the way. forward_weight_data.duration = parsed_way.duration / num_edges; forward_weight_data.type = InternalExtractorEdge::WeightType::WAY_DURATION; backward_weight_data.duration = parsed_way.duration / num_edges; backward_weight_data.type = InternalExtractorEdge::WeightType::WAY_DURATION; } else { if (parsed_way.forward_speed > 0 && parsed_way.forward_travel_mode != TRAVEL_MODE_INACCESSIBLE) { forward_weight_data.speed = parsed_way.forward_speed; forward_weight_data.type = InternalExtractorEdge::WeightType::SPEED; } if (parsed_way.backward_speed > 0 && parsed_way.backward_travel_mode != TRAVEL_MODE_INACCESSIBLE) { backward_weight_data.speed = parsed_way.backward_speed; backward_weight_data.type = InternalExtractorEdge::WeightType::SPEED; } } if (forward_weight_data.type == InternalExtractorEdge::WeightType::INVALID && backward_weight_data.type == InternalExtractorEdge::WeightType::INVALID) { SimpleLogger().Write(logDEBUG) << "found way with bogus speed, id: " << input_way.id(); return; } // Get the unique identifier for the street name const auto &string_map_iterator = string_map.find(parsed_way.name); unsigned name_id = external_memory.name_list.size(); if (string_map.end() == string_map_iterator) { external_memory.name_list.push_back(parsed_way.name); string_map.insert(std::make_pair(parsed_way.name, name_id)); } else { name_id = string_map_iterator->second; } const bool split_edge = (parsed_way.forward_speed > 0) && (TRAVEL_MODE_INACCESSIBLE != parsed_way.forward_travel_mode) && (parsed_way.backward_speed > 0) && (TRAVEL_MODE_INACCESSIBLE != parsed_way.backward_travel_mode) && ((parsed_way.forward_speed != parsed_way.backward_speed) || (parsed_way.forward_travel_mode != parsed_way.backward_travel_mode)); // lambda to add edge to container auto pair_wise_segment_split_forward = [&](const osmium::NodeRef &first_node, const osmium::NodeRef &last_node) { const bool forward_only = split_edge || TRAVEL_MODE_INACCESSIBLE == parsed_way.backward_travel_mode; external_memory.all_edges_list.push_back(InternalExtractorEdge( first_node.ref(), last_node.ref(), name_id, forward_weight_data, true, !forward_only, parsed_way.roundabout, parsed_way.ignore_in_grid, parsed_way.is_access_restricted, parsed_way.forward_travel_mode, split_edge)); external_memory.used_node_id_list.push_back(first_node.ref()); }; const bool is_opposite_way = TRAVEL_MODE_INACCESSIBLE == parsed_way.forward_travel_mode; // traverse way in reverse in this case if (is_opposite_way) { // why don't we have to swap the parsed_way.forward/backward speed here as well const_cast<ExtractionWay &>(parsed_way).forward_travel_mode = parsed_way.backward_travel_mode; const_cast<ExtractionWay &>(parsed_way).backward_travel_mode = TRAVEL_MODE_INACCESSIBLE; osrm::for_each_pair(input_way.nodes().crbegin(), input_way.nodes().crend(), pair_wise_segment_split_forward); external_memory.used_node_id_list.push_back(input_way.nodes().front().ref()); } else { osrm::for_each_pair(input_way.nodes().cbegin(), input_way.nodes().cend(), pair_wise_segment_split_forward); external_memory.used_node_id_list.push_back(input_way.nodes().back().ref()); } // The following information is needed to identify start and end segments of restrictions external_memory.way_start_end_id_list.push_back( {(EdgeID)input_way.id(), (NodeID)input_way.nodes()[0].ref(), (NodeID)input_way.nodes()[1].ref(), (NodeID)input_way.nodes()[input_way.nodes().size() - 2].ref(), (NodeID)input_way.nodes().back().ref()}); if (split_edge) { // Only true if the way should be split BOOST_ASSERT(parsed_way.backward_travel_mode != TRAVEL_MODE_INACCESSIBLE); auto pair_wise_segment_split_2 = [&](const osmium::NodeRef &first_node, const osmium::NodeRef &last_node) { external_memory.all_edges_list.push_back(InternalExtractorEdge( last_node.ref(), first_node.ref(), name_id, backward_weight_data, true, false, parsed_way.roundabout, parsed_way.ignore_in_grid, parsed_way.is_access_restricted, parsed_way.backward_travel_mode, split_edge)); external_memory.used_node_id_list.push_back(last_node.ref()); }; if (is_opposite_way) { osrm::for_each_pair(input_way.nodes().crbegin(), input_way.nodes().crend(), pair_wise_segment_split_2); external_memory.used_node_id_list.push_back(input_way.nodes().front().ref()); } else { osrm::for_each_pair(input_way.nodes().cbegin(), input_way.nodes().cend(), pair_wise_segment_split_2); external_memory.used_node_id_list.push_back(input_way.nodes().front().ref()); } external_memory.way_start_end_id_list.push_back( {(EdgeID)input_way.id(), (NodeID)input_way.nodes()[1].ref(), (NodeID)input_way.nodes()[0].ref(), (NodeID)input_way.nodes().back().ref(), (NodeID)input_way.nodes()[input_way.nodes().size() - 2].ref()}); } }
static InternalExtractorEdge max_osm_value() { return InternalExtractorEdge(MAX_OSM_NODEID, MAX_OSM_NODEID, 0, WeightData(), false, false, false, false, true, TRAVEL_MODE_INACCESSIBLE, false, guidance::RoadClassificationData()); }