2017-03-07 18:30:49 -05:00
|
|
|
#include "updater/updater.hpp"
|
2017-03-07 19:38:08 -05:00
|
|
|
#include "updater/csv_source.hpp"
|
|
|
|
|
2017-03-07 18:30:49 -05:00
|
|
|
#include "extractor/compressed_edge_container.hpp"
|
|
|
|
#include "extractor/edge_based_graph_factory.hpp"
|
2017-04-01 21:25:55 -04:00
|
|
|
#include "extractor/files.hpp"
|
2017-05-11 06:13:52 -04:00
|
|
|
#include "extractor/packed_osm_ids.hpp"
|
|
|
|
#include "extractor/restriction.hpp"
|
2017-08-01 11:18:12 -04:00
|
|
|
#include "extractor/serialization.hpp"
|
2017-03-07 18:30:49 -05:00
|
|
|
|
2018-01-05 08:33:53 -05:00
|
|
|
#include "guidance/files.hpp"
|
|
|
|
|
2017-03-07 18:30:49 -05:00
|
|
|
#include "util/exception.hpp"
|
|
|
|
#include "util/exception_utils.hpp"
|
2017-03-13 07:25:03 -04:00
|
|
|
#include "util/for_each_pair.hpp"
|
2017-03-07 18:30:49 -05:00
|
|
|
#include "util/integer_range.hpp"
|
|
|
|
#include "util/log.hpp"
|
2018-03-22 11:40:57 -04:00
|
|
|
#include "util/mmap_tar.hpp"
|
2017-05-11 06:13:52 -04:00
|
|
|
#include "util/opening_hours.hpp"
|
2017-03-07 18:30:49 -05:00
|
|
|
#include "util/static_rtree.hpp"
|
|
|
|
#include "util/string_util.hpp"
|
2017-05-11 06:13:52 -04:00
|
|
|
#include "util/timezones.hpp"
|
2017-03-07 18:30:49 -05:00
|
|
|
#include "util/timing_util.hpp"
|
|
|
|
#include "util/typedefs.hpp"
|
|
|
|
|
|
|
|
#include <boost/assert.hpp>
|
|
|
|
#include <boost/filesystem/fstream.hpp>
|
|
|
|
|
|
|
|
#include <tbb/blocked_range.h>
|
2018-01-04 17:28:19 -05:00
|
|
|
#include <tbb/concurrent_vector.h>
|
2017-03-07 18:30:49 -05:00
|
|
|
#include <tbb/enumerable_thread_specific.h>
|
2018-01-04 17:28:19 -05:00
|
|
|
#include <tbb/parallel_for.h>
|
2017-03-07 18:30:49 -05:00
|
|
|
#include <tbb/parallel_invoke.h>
|
2018-01-04 17:28:19 -05:00
|
|
|
#include <tbb/parallel_sort.h>
|
2017-03-07 18:30:49 -05:00
|
|
|
|
|
|
|
#include <algorithm>
|
2017-04-11 07:06:22 -04:00
|
|
|
#include <atomic>
|
2017-03-07 18:30:49 -05:00
|
|
|
#include <bitset>
|
|
|
|
#include <cstdint>
|
|
|
|
#include <iterator>
|
|
|
|
#include <memory>
|
|
|
|
#include <tuple>
|
|
|
|
#include <vector>
|
|
|
|
|
2017-05-11 06:13:52 -04:00
|
|
|
namespace std
|
|
|
|
{
|
|
|
|
template <typename T1, typename T2, typename T3> struct hash<std::tuple<T1, T2, T3>>
|
|
|
|
{
|
|
|
|
size_t operator()(const std::tuple<T1, T2, T3> &t) const
|
|
|
|
{
|
|
|
|
return hash_val(std::get<0>(t), std::get<1>(t), std::get<2>(t));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename T1, typename T2> struct hash<std::tuple<T1, T2>>
|
|
|
|
{
|
|
|
|
size_t operator()(const std::tuple<T1, T2> &t) const
|
|
|
|
{
|
|
|
|
return hash_val(std::get<0>(t), std::get<1>(t));
|
|
|
|
}
|
|
|
|
};
|
2020-11-26 10:21:39 -05:00
|
|
|
} // namespace std
|
2017-05-11 06:13:52 -04:00
|
|
|
|
2017-03-10 20:07:52 -05:00
|
|
|
namespace osrm
|
|
|
|
{
|
|
|
|
namespace updater
|
|
|
|
{
|
2017-03-07 18:30:49 -05:00
|
|
|
namespace
|
|
|
|
{
|
|
|
|
|
|
|
|
template <typename T> inline bool is_aligned(const void *pointer)
|
|
|
|
{
|
|
|
|
static_assert(sizeof(T) % alignof(T) == 0, "pointer can not be used as an array pointer");
|
|
|
|
return reinterpret_cast<uintptr_t>(pointer) % alignof(T) == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns duration in deci-seconds
|
2017-05-10 19:04:09 -04:00
|
|
|
inline SegmentDuration convertToDuration(double speed_in_kmh, double distance_in_meters)
|
2017-03-07 18:30:49 -05:00
|
|
|
{
|
|
|
|
if (speed_in_kmh <= 0.)
|
2017-05-10 19:04:09 -04:00
|
|
|
return INVALID_SEGMENT_DURATION;
|
2017-03-07 18:30:49 -05:00
|
|
|
|
2017-04-10 10:44:48 -04:00
|
|
|
const auto speed_in_ms = speed_in_kmh / 3.6;
|
|
|
|
const auto duration = distance_in_meters / speed_in_ms;
|
2017-05-10 19:04:09 -04:00
|
|
|
auto segment_duration = std::max<SegmentDuration>(
|
|
|
|
1, boost::numeric_cast<SegmentDuration>(std::round(duration * 10.)));
|
|
|
|
if (segment_duration >= INVALID_SEGMENT_DURATION)
|
|
|
|
{
|
|
|
|
util::Log(logWARNING) << "Clamping segment duration " << segment_duration << " to "
|
|
|
|
<< MAX_SEGMENT_DURATION;
|
|
|
|
segment_duration = MAX_SEGMENT_DURATION;
|
|
|
|
}
|
|
|
|
return segment_duration;
|
2017-03-07 18:30:49 -05:00
|
|
|
}
|
|
|
|
|
2017-03-10 06:03:45 -05:00
|
|
|
#if !defined(NDEBUG)
|
2017-03-10 20:07:52 -05:00
|
|
|
void checkWeightsConsistency(
|
2017-03-07 18:30:49 -05:00
|
|
|
const UpdaterConfig &config,
|
|
|
|
const std::vector<osrm::extractor::EdgeBasedEdge> &edge_based_edge_list)
|
|
|
|
{
|
2017-03-13 07:25:03 -04:00
|
|
|
extractor::SegmentDataContainer segment_data;
|
2017-06-16 04:45:24 -04:00
|
|
|
extractor::files::readSegmentData(config.GetPath(".osrm.geometry"), segment_data);
|
2017-03-07 18:30:49 -05:00
|
|
|
|
2017-04-25 05:36:34 -04:00
|
|
|
extractor::EdgeBasedNodeDataContainer node_data;
|
2017-06-16 04:45:24 -04:00
|
|
|
extractor::files::readNodeData(config.GetPath(".osrm.ebg_nodes"), node_data);
|
2017-04-25 05:36:34 -04:00
|
|
|
|
2017-03-07 18:30:49 -05:00
|
|
|
for (auto &edge : edge_based_edge_list)
|
|
|
|
{
|
2017-05-03 10:16:29 -04:00
|
|
|
const auto node_id = edge.source;
|
2017-04-25 05:36:34 -04:00
|
|
|
const auto geometry_id = node_data.GetGeometryID(node_id);
|
2017-03-07 18:30:49 -05:00
|
|
|
|
2017-03-13 07:25:03 -04:00
|
|
|
if (geometry_id.forward)
|
|
|
|
{
|
|
|
|
auto range = segment_data.GetForwardWeights(geometry_id.id);
|
2022-06-27 19:14:28 -04:00
|
|
|
// NOLINTNEXTLINE(bugprone-fold-init-type)
|
2017-03-16 17:47:27 -04:00
|
|
|
EdgeWeight weight = std::accumulate(range.begin(), range.end(), EdgeWeight{0});
|
2017-03-13 07:25:03 -04:00
|
|
|
if (weight > edge.data.weight)
|
|
|
|
{
|
2017-03-10 04:57:07 -05:00
|
|
|
util::Log(logWARNING) << geometry_id.id << " vs " << edge.data.turn_id << ":"
|
2017-03-14 11:34:22 -04:00
|
|
|
<< weight << " > " << edge.data.weight;
|
2017-03-13 07:25:03 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
auto range = segment_data.GetReverseWeights(geometry_id.id);
|
2022-06-27 19:14:28 -04:00
|
|
|
// NOLINTNEXTLINE(bugprone-fold-init-type)
|
2017-03-16 17:47:27 -04:00
|
|
|
EdgeWeight weight = std::accumulate(range.begin(), range.end(), EdgeWeight{0});
|
2017-03-13 07:25:03 -04:00
|
|
|
if (weight > edge.data.weight)
|
|
|
|
{
|
2017-03-10 04:57:07 -05:00
|
|
|
util::Log(logWARNING) << geometry_id.id << " vs " << edge.data.turn_id << ":"
|
2017-03-14 11:34:22 -04:00
|
|
|
<< weight << " > " << edge.data.weight;
|
2017-03-13 07:25:03 -04:00
|
|
|
}
|
|
|
|
}
|
2017-03-07 18:30:49 -05:00
|
|
|
}
|
|
|
|
}
|
2017-03-10 06:03:45 -05:00
|
|
|
#endif
|
2017-03-07 18:30:49 -05:00
|
|
|
|
2018-02-06 06:06:35 -05:00
|
|
|
static const constexpr std::size_t LUA_SOURCE = 0;
|
|
|
|
|
2017-03-14 19:39:52 -04:00
|
|
|
tbb::concurrent_vector<GeometryID>
|
|
|
|
updateSegmentData(const UpdaterConfig &config,
|
|
|
|
const extractor::ProfileProperties &profile_properties,
|
|
|
|
const SegmentLookupTable &segment_speed_lookup,
|
2017-05-11 06:13:52 -04:00
|
|
|
extractor::SegmentDataContainer &segment_data,
|
|
|
|
std::vector<util::Coordinate> &coordinates,
|
|
|
|
extractor::PackedOSMIDs &osm_node_ids)
|
2017-03-10 20:07:52 -05:00
|
|
|
{
|
|
|
|
// vector to count used speeds for logging
|
|
|
|
// size offset by one since index 0 is used for speeds not from external file
|
|
|
|
using counters_type = std::vector<std::size_t>;
|
|
|
|
std::size_t num_counters = config.segment_speed_lookup_paths.size() + 1;
|
|
|
|
tbb::enumerable_thread_specific<counters_type> segment_speeds_counters(
|
|
|
|
counters_type(num_counters, 0));
|
|
|
|
|
2017-04-11 07:06:22 -04:00
|
|
|
// closure to convert SpeedSource value to weight and count fallbacks to durations
|
|
|
|
std::atomic<std::uint32_t> fallbacks_to_duration{0};
|
2020-11-26 10:21:39 -05:00
|
|
|
auto convertToWeight = [&profile_properties,
|
|
|
|
&fallbacks_to_duration](const SegmentWeight &existing_weight,
|
|
|
|
const SpeedSource &value,
|
|
|
|
double distance_in_meters) {
|
2017-08-31 17:51:05 -04:00
|
|
|
double rate = std::numeric_limits<double>::quiet_NaN();
|
|
|
|
|
|
|
|
// if value.rate is not set, we fall back to duration
|
|
|
|
// this happens when there is no 4th column in the input CSV
|
|
|
|
// if value.rate is set but NaN, we keep the existing weight
|
|
|
|
// this happens when there is an empty 4th column in the input CSV
|
|
|
|
// otherwise, we use the value as the new rate
|
|
|
|
if (!value.rate)
|
|
|
|
{
|
2017-04-11 07:06:22 -04:00
|
|
|
++fallbacks_to_duration;
|
|
|
|
rate = value.speed / 3.6;
|
|
|
|
}
|
2017-08-31 17:51:05 -04:00
|
|
|
else
|
|
|
|
{
|
|
|
|
rate = *value.rate;
|
|
|
|
if (!std::isfinite(rate))
|
|
|
|
{
|
|
|
|
return existing_weight;
|
|
|
|
}
|
|
|
|
}
|
2017-04-11 07:06:22 -04:00
|
|
|
|
|
|
|
if (rate <= 0.)
|
2017-05-10 19:04:09 -04:00
|
|
|
return INVALID_SEGMENT_WEIGHT;
|
2017-04-11 07:06:22 -04:00
|
|
|
|
|
|
|
const auto weight_multiplier = profile_properties.GetWeightMultiplier();
|
|
|
|
const auto weight = distance_in_meters / rate;
|
2017-05-10 19:04:09 -04:00
|
|
|
auto segment_weight = std::max<SegmentWeight>(
|
|
|
|
1, boost::numeric_cast<SegmentWeight>(std::round(weight * weight_multiplier)));
|
|
|
|
if (segment_weight >= INVALID_SEGMENT_WEIGHT)
|
|
|
|
{
|
|
|
|
util::Log(logWARNING) << "Clamping segment weight " << segment_weight << " to "
|
|
|
|
<< MAX_SEGMENT_WEIGHT;
|
|
|
|
segment_weight = MAX_SEGMENT_WEIGHT;
|
|
|
|
}
|
|
|
|
return segment_weight;
|
2017-04-11 07:06:22 -04:00
|
|
|
};
|
|
|
|
|
2017-03-14 11:34:22 -04:00
|
|
|
// The check here is enabled by the `--edge-weight-updates-over-factor` flag it logs a
|
|
|
|
// warning if the new duration exceeds a heuristic of what a reasonable duration update is
|
|
|
|
std::unique_ptr<extractor::SegmentDataContainer> segment_data_backup;
|
|
|
|
if (config.log_edge_updates_factor > 0)
|
|
|
|
{
|
|
|
|
// copy the old data so we can compare later
|
|
|
|
segment_data_backup = std::make_unique<extractor::SegmentDataContainer>(segment_data);
|
|
|
|
}
|
|
|
|
|
2017-03-14 12:04:38 -04:00
|
|
|
tbb::concurrent_vector<GeometryID> updated_segments;
|
|
|
|
|
2017-03-10 20:56:35 -05:00
|
|
|
using DirectionalGeometryID = extractor::SegmentDataContainer::DirectionalGeometryID;
|
|
|
|
auto range = tbb::blocked_range<DirectionalGeometryID>(0, segment_data.GetNumberOfGeometries());
|
2018-02-02 06:59:30 -05:00
|
|
|
tbb::parallel_for(range, [&](const auto &range) {
|
2017-03-10 20:07:52 -05:00
|
|
|
auto &counters = segment_speeds_counters.local();
|
2017-03-10 20:56:35 -05:00
|
|
|
std::vector<double> segment_lengths;
|
|
|
|
for (auto geometry_id = range.begin(); geometry_id < range.end(); geometry_id++)
|
2017-03-10 20:07:52 -05:00
|
|
|
{
|
|
|
|
auto nodes_range = segment_data.GetForwardGeometry(geometry_id);
|
|
|
|
|
2017-03-14 11:34:22 -04:00
|
|
|
segment_lengths.clear();
|
2017-03-13 07:25:03 -04:00
|
|
|
segment_lengths.reserve(nodes_range.size() + 1);
|
2017-03-13 19:51:28 -04:00
|
|
|
util::for_each_pair(nodes_range, [&](const auto &u, const auto &v) {
|
2017-03-10 20:56:35 -05:00
|
|
|
segment_lengths.push_back(util::coordinate_calculation::greatCircleDistance(
|
2017-04-02 19:58:06 -04:00
|
|
|
coordinates[u], coordinates[v]));
|
2017-03-10 20:56:35 -05:00
|
|
|
});
|
2017-03-10 20:07:52 -05:00
|
|
|
|
2017-03-10 20:56:35 -05:00
|
|
|
auto fwd_weights_range = segment_data.GetForwardWeights(geometry_id);
|
|
|
|
auto fwd_durations_range = segment_data.GetForwardDurations(geometry_id);
|
|
|
|
auto fwd_datasources_range = segment_data.GetForwardDatasources(geometry_id);
|
2017-03-14 12:04:38 -04:00
|
|
|
bool fwd_was_updated = false;
|
2017-03-16 17:47:27 -04:00
|
|
|
for (const auto segment_offset : util::irange<std::size_t>(0, fwd_weights_range.size()))
|
2017-03-10 20:07:52 -05:00
|
|
|
{
|
2017-04-02 19:58:06 -04:00
|
|
|
auto u = osm_node_ids[nodes_range[segment_offset]];
|
|
|
|
auto v = osm_node_ids[nodes_range[segment_offset + 1]];
|
2017-08-16 14:53:21 -04:00
|
|
|
|
|
|
|
// Self-loops are artifical segments (e.g. traffic light nodes), do not
|
|
|
|
// waste time updating them with traffic data
|
|
|
|
if (u == v)
|
|
|
|
continue;
|
|
|
|
|
2017-03-10 20:56:35 -05:00
|
|
|
if (auto value = segment_speed_lookup({u, v}))
|
|
|
|
{
|
2017-04-10 10:44:48 -04:00
|
|
|
auto segment_length = segment_lengths[segment_offset];
|
|
|
|
auto new_duration = convertToDuration(value->speed, segment_length);
|
2017-08-31 17:51:05 -04:00
|
|
|
auto new_weight =
|
|
|
|
convertToWeight(fwd_weights_range[segment_offset], *value, segment_length);
|
2017-03-14 12:04:38 -04:00
|
|
|
fwd_was_updated = true;
|
2017-03-14 11:34:22 -04:00
|
|
|
|
|
|
|
fwd_weights_range[segment_offset] = new_weight;
|
|
|
|
fwd_durations_range[segment_offset] = new_duration;
|
2017-03-10 20:56:35 -05:00
|
|
|
fwd_datasources_range[segment_offset] = value->source;
|
|
|
|
counters[value->source] += 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
counters[LUA_SOURCE] += 1;
|
|
|
|
}
|
2017-03-10 20:07:52 -05:00
|
|
|
}
|
2017-03-14 12:04:38 -04:00
|
|
|
if (fwd_was_updated)
|
2017-03-14 16:48:44 -04:00
|
|
|
updated_segments.push_back(GeometryID{geometry_id, true});
|
2017-03-10 20:07:52 -05:00
|
|
|
|
2017-03-10 20:56:35 -05:00
|
|
|
// In this case we want it oriented from in forward directions
|
2017-03-14 11:34:22 -04:00
|
|
|
auto rev_weights_range =
|
|
|
|
boost::adaptors::reverse(segment_data.GetReverseWeights(geometry_id));
|
|
|
|
auto rev_durations_range =
|
|
|
|
boost::adaptors::reverse(segment_data.GetReverseDurations(geometry_id));
|
|
|
|
auto rev_datasources_range =
|
|
|
|
boost::adaptors::reverse(segment_data.GetReverseDatasources(geometry_id));
|
2017-03-14 12:04:38 -04:00
|
|
|
bool rev_was_updated = false;
|
2017-03-10 20:56:35 -05:00
|
|
|
|
2017-03-16 17:47:27 -04:00
|
|
|
for (const auto segment_offset : util::irange<std::size_t>(0, rev_weights_range.size()))
|
2017-03-10 20:07:52 -05:00
|
|
|
{
|
2017-04-02 19:58:06 -04:00
|
|
|
auto u = osm_node_ids[nodes_range[segment_offset]];
|
|
|
|
auto v = osm_node_ids[nodes_range[segment_offset + 1]];
|
2017-08-16 14:53:21 -04:00
|
|
|
|
|
|
|
// Self-loops are artifical segments (e.g. traffic light nodes), do not
|
|
|
|
// waste time updating them with traffic data
|
|
|
|
if (u == v)
|
|
|
|
continue;
|
|
|
|
|
2017-03-10 20:56:35 -05:00
|
|
|
if (auto value = segment_speed_lookup({v, u}))
|
|
|
|
{
|
2017-04-10 10:44:48 -04:00
|
|
|
auto segment_length = segment_lengths[segment_offset];
|
|
|
|
auto new_duration = convertToDuration(value->speed, segment_length);
|
2017-08-31 17:51:05 -04:00
|
|
|
auto new_weight =
|
|
|
|
convertToWeight(rev_weights_range[segment_offset], *value, segment_length);
|
2017-03-14 12:04:38 -04:00
|
|
|
rev_was_updated = true;
|
2017-03-14 11:34:22 -04:00
|
|
|
|
|
|
|
rev_weights_range[segment_offset] = new_weight;
|
|
|
|
rev_durations_range[segment_offset] = new_duration;
|
2017-03-10 20:56:35 -05:00
|
|
|
rev_datasources_range[segment_offset] = value->source;
|
|
|
|
counters[value->source] += 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
counters[LUA_SOURCE] += 1;
|
|
|
|
}
|
2017-03-10 20:07:52 -05:00
|
|
|
}
|
2017-03-14 12:04:38 -04:00
|
|
|
if (rev_was_updated)
|
2017-03-14 16:48:44 -04:00
|
|
|
updated_segments.push_back(GeometryID{geometry_id, false});
|
2017-03-10 20:07:52 -05:00
|
|
|
}
|
2017-03-10 20:56:35 -05:00
|
|
|
}); // parallel_for
|
2017-03-10 20:07:52 -05:00
|
|
|
|
|
|
|
counters_type merged_counters(num_counters, 0);
|
|
|
|
for (const auto &counters : segment_speeds_counters)
|
|
|
|
{
|
|
|
|
for (std::size_t i = 0; i < counters.size(); i++)
|
|
|
|
{
|
|
|
|
merged_counters[i] += counters[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (std::size_t i = 0; i < merged_counters.size(); i++)
|
|
|
|
{
|
|
|
|
if (i == LUA_SOURCE)
|
|
|
|
{
|
|
|
|
util::Log() << "Used " << merged_counters[LUA_SOURCE]
|
|
|
|
<< " speeds from LUA profile or input map";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// segments_speeds_counters has 0 as LUA, segment_speed_filenames not, thus we need
|
|
|
|
// to susbstract 1 to avoid off-by-one error
|
|
|
|
util::Log() << "Used " << merged_counters[i] << " speeds from "
|
|
|
|
<< config.segment_speed_lookup_paths[i - 1];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-11 07:06:22 -04:00
|
|
|
if (!profile_properties.fallback_to_duration && fallbacks_to_duration > 0)
|
|
|
|
{
|
|
|
|
util::Log(logWARNING) << "Speed values were used to update " << fallbacks_to_duration
|
|
|
|
<< " segments for '" << profile_properties.GetWeightName()
|
|
|
|
<< "' profile";
|
|
|
|
}
|
|
|
|
|
2017-03-14 11:34:22 -04:00
|
|
|
if (config.log_edge_updates_factor > 0)
|
|
|
|
{
|
|
|
|
BOOST_ASSERT(segment_data_backup);
|
|
|
|
|
2017-03-16 17:47:27 -04:00
|
|
|
for (const auto geometry_id :
|
|
|
|
util::irange<DirectionalGeometryID>(0, segment_data.GetNumberOfGeometries()))
|
2017-03-14 11:34:22 -04:00
|
|
|
{
|
|
|
|
auto nodes_range = segment_data.GetForwardGeometry(geometry_id);
|
|
|
|
|
|
|
|
auto new_fwd_durations_range = segment_data.GetForwardDurations(geometry_id);
|
|
|
|
auto new_fwd_datasources_range = segment_data.GetForwardDatasources(geometry_id);
|
|
|
|
auto new_rev_durations_range =
|
|
|
|
boost::adaptors::reverse(segment_data.GetReverseDurations(geometry_id));
|
2017-07-27 13:24:34 -04:00
|
|
|
auto new_rev_datasources_range = segment_data.GetReverseDatasources(geometry_id);
|
2017-03-14 11:34:22 -04:00
|
|
|
auto old_fwd_durations_range = segment_data_backup->GetForwardDurations(geometry_id);
|
|
|
|
auto old_rev_durations_range =
|
|
|
|
boost::adaptors::reverse(segment_data_backup->GetReverseDurations(geometry_id));
|
|
|
|
|
2017-03-16 17:47:27 -04:00
|
|
|
for (const auto segment_offset :
|
|
|
|
util::irange<std::size_t>(0, new_fwd_durations_range.size()))
|
2017-03-14 11:34:22 -04:00
|
|
|
{
|
|
|
|
if (new_fwd_datasources_range[segment_offset] == LUA_SOURCE)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (old_fwd_durations_range[segment_offset] >=
|
|
|
|
(new_fwd_durations_range[segment_offset] * config.log_edge_updates_factor))
|
|
|
|
{
|
2017-04-02 19:58:06 -04:00
|
|
|
auto from = osm_node_ids[nodes_range[segment_offset]];
|
|
|
|
auto to = osm_node_ids[nodes_range[segment_offset + 1]];
|
2017-03-14 11:34:22 -04:00
|
|
|
util::Log(logWARNING)
|
|
|
|
<< "[weight updates] Edge weight update from "
|
|
|
|
<< old_fwd_durations_range[segment_offset] / 10. << "s to "
|
|
|
|
<< new_fwd_durations_range[segment_offset] / 10. << "s Segment: " << from
|
|
|
|
<< "," << to << " based on "
|
|
|
|
<< config.segment_speed_lookup_paths
|
|
|
|
[new_fwd_datasources_range[segment_offset] - 1];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-16 17:47:27 -04:00
|
|
|
for (const auto segment_offset :
|
|
|
|
util::irange<std::size_t>(0, new_rev_durations_range.size()))
|
2017-03-14 11:34:22 -04:00
|
|
|
{
|
|
|
|
if (new_rev_datasources_range[segment_offset] == LUA_SOURCE)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (old_rev_durations_range[segment_offset] >=
|
|
|
|
(new_rev_durations_range[segment_offset] * config.log_edge_updates_factor))
|
|
|
|
{
|
2017-04-02 19:58:06 -04:00
|
|
|
auto from = osm_node_ids[nodes_range[segment_offset + 1]];
|
|
|
|
auto to = osm_node_ids[nodes_range[segment_offset]];
|
2017-03-14 11:34:22 -04:00
|
|
|
util::Log(logWARNING)
|
|
|
|
<< "[weight updates] Edge weight update from "
|
|
|
|
<< old_rev_durations_range[segment_offset] / 10. << "s to "
|
|
|
|
<< new_rev_durations_range[segment_offset] / 10. << "s Segment: " << from
|
|
|
|
<< "," << to << " based on "
|
|
|
|
<< config.segment_speed_lookup_paths
|
|
|
|
[new_rev_datasources_range[segment_offset] - 1];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-14 19:39:52 -04:00
|
|
|
return updated_segments;
|
2017-03-10 20:20:22 -05:00
|
|
|
}
|
2017-03-10 20:07:52 -05:00
|
|
|
|
2017-03-10 20:20:22 -05:00
|
|
|
void saveDatasourcesNames(const UpdaterConfig &config)
|
|
|
|
{
|
|
|
|
extractor::Datasources sources;
|
|
|
|
DatasourceID source = 0;
|
2017-03-16 17:47:27 -04:00
|
|
|
sources.SetSourceName(source, "lua profile");
|
|
|
|
source++;
|
2017-03-10 20:20:22 -05:00
|
|
|
|
|
|
|
// Only write the filename, without path or extension.
|
|
|
|
// This prevents information leakage, and keeps names short
|
|
|
|
// for rendering in the debug tiles.
|
|
|
|
for (auto const &name : config.segment_speed_lookup_paths)
|
|
|
|
{
|
2017-03-16 17:47:27 -04:00
|
|
|
sources.SetSourceName(source, boost::filesystem::path(name).stem().string());
|
|
|
|
source++;
|
2017-03-10 20:20:22 -05:00
|
|
|
}
|
2017-03-10 20:07:52 -05:00
|
|
|
|
2017-06-16 04:45:24 -04:00
|
|
|
extractor::files::writeDatasources(config.GetPath(".osrm.datasource_names"), sources);
|
2017-03-10 20:07:52 -05:00
|
|
|
}
|
2017-03-14 18:54:57 -04:00
|
|
|
|
2017-03-14 19:39:52 -04:00
|
|
|
std::vector<std::uint64_t>
|
|
|
|
updateTurnPenalties(const UpdaterConfig &config,
|
|
|
|
const extractor::ProfileProperties &profile_properties,
|
|
|
|
const TurnLookupTable &turn_penalty_lookup,
|
|
|
|
std::vector<TurnPenalty> &turn_weight_penalties,
|
2017-05-11 06:13:52 -04:00
|
|
|
std::vector<TurnPenalty> &turn_duration_penalties,
|
|
|
|
extractor::PackedOSMIDs osm_node_ids)
|
2017-03-14 18:54:57 -04:00
|
|
|
{
|
|
|
|
const auto weight_multiplier = profile_properties.GetWeightMultiplier();
|
|
|
|
|
2020-10-25 21:19:17 -04:00
|
|
|
// [NOTE] turn_index_blocks could be simply loaded by `files::readTurnPenaltiesIndex()`,
|
|
|
|
// however, we leave the below mmap to keep compatiblity.
|
|
|
|
// Use `files::readTurnPenaltiesIndex()` instead once the compatiblity is not that
|
|
|
|
// important.
|
2017-03-14 18:54:57 -04:00
|
|
|
// Mapped file pointer for turn indices
|
2017-05-19 18:28:01 -04:00
|
|
|
boost::iostreams::mapped_file_source turn_index_region;
|
2018-03-22 11:40:57 -04:00
|
|
|
const extractor::lookup::TurnIndexBlock *turn_index_blocks;
|
|
|
|
{
|
|
|
|
auto map =
|
|
|
|
util::mmapTarFile(config.GetPath(".osrm.turn_penalties_index"), turn_index_region);
|
2018-03-22 14:26:40 -04:00
|
|
|
turn_index_blocks = reinterpret_cast<const extractor::lookup::TurnIndexBlock *>(
|
|
|
|
map["/extractor/turn_index"].first);
|
2018-03-22 11:40:57 -04:00
|
|
|
}
|
2017-03-14 18:54:57 -04:00
|
|
|
|
2017-05-11 06:13:52 -04:00
|
|
|
// Get the turn penalty and update to the new value if required
|
2017-03-14 19:39:52 -04:00
|
|
|
std::vector<std::uint64_t> updated_turns;
|
2017-03-14 18:54:57 -04:00
|
|
|
for (std::uint64_t edge_index = 0; edge_index < turn_weight_penalties.size(); ++edge_index)
|
|
|
|
{
|
2017-05-11 06:13:52 -04:00
|
|
|
// edges are stored by internal OSRM ids, these need to be mapped back to OSM ids
|
|
|
|
const extractor::lookup::TurnIndexBlock internal_turn = turn_index_blocks[edge_index];
|
|
|
|
const Turn osm_turn{osm_node_ids[internal_turn.from_id],
|
|
|
|
osm_node_ids[internal_turn.via_id],
|
|
|
|
osm_node_ids[internal_turn.to_id]};
|
|
|
|
// original turn weight/duration values
|
2017-03-14 18:54:57 -04:00
|
|
|
auto turn_weight_penalty = turn_weight_penalties[edge_index];
|
|
|
|
auto turn_duration_penalty = turn_duration_penalties[edge_index];
|
2017-05-11 06:13:52 -04:00
|
|
|
|
|
|
|
if (auto value = turn_penalty_lookup(osm_turn))
|
2017-03-14 18:54:57 -04:00
|
|
|
{
|
|
|
|
turn_duration_penalty =
|
|
|
|
boost::numeric_cast<TurnPenalty>(std::round(value->duration * 10.));
|
|
|
|
turn_weight_penalty = boost::numeric_cast<TurnPenalty>(std::round(
|
|
|
|
std::isfinite(value->weight) ? value->weight * weight_multiplier
|
|
|
|
: turn_duration_penalty * weight_multiplier / 10.));
|
|
|
|
|
|
|
|
turn_duration_penalties[edge_index] = turn_duration_penalty;
|
|
|
|
turn_weight_penalties[edge_index] = turn_weight_penalty;
|
2017-03-14 19:39:52 -04:00
|
|
|
updated_turns.push_back(edge_index);
|
2017-03-14 18:54:57 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (turn_weight_penalty < 0)
|
|
|
|
{
|
2017-05-11 06:13:52 -04:00
|
|
|
util::Log(logWARNING) << "Negative turn penalty at " << osm_turn.from << ", "
|
|
|
|
<< osm_turn.via << ", " << osm_turn.to << ": turn penalty "
|
|
|
|
<< turn_weight_penalty;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return updated_turns;
|
|
|
|
}
|
|
|
|
|
2017-08-01 11:18:12 -04:00
|
|
|
bool IsRestrictionValid(const Timezoner &tz_handler, const extractor::ConditionalTurnPenalty &turn)
|
2017-05-11 06:13:52 -04:00
|
|
|
{
|
2017-08-01 11:18:12 -04:00
|
|
|
BOOST_ASSERT(!turn.conditions.empty());
|
2017-05-11 06:13:52 -04:00
|
|
|
|
2017-07-06 11:09:24 -04:00
|
|
|
// we utilize the via node (first on ways) to represent the turn restriction
|
2017-08-01 11:18:12 -04:00
|
|
|
auto const via = turn.location;
|
2017-07-06 11:09:24 -04:00
|
|
|
|
2017-08-01 11:18:12 -04:00
|
|
|
const auto lon = static_cast<double>(toFloating(via.lon));
|
|
|
|
const auto lat = static_cast<double>(toFloating(via.lat));
|
|
|
|
const auto &conditions = turn.conditions;
|
2017-05-11 06:13:52 -04:00
|
|
|
|
|
|
|
// Get local time of the restriction
|
|
|
|
const auto &local_time = tz_handler(point_t{lon, lat});
|
2017-06-01 09:55:40 -04:00
|
|
|
if (!local_time)
|
|
|
|
return false;
|
2017-05-11 06:13:52 -04:00
|
|
|
|
|
|
|
// TODO: check restriction type [:<transportation mode>][:<direction>]
|
|
|
|
// http://wiki.openstreetmap.org/wiki/Conditional_restrictions#Tagging
|
|
|
|
|
|
|
|
// TODO: parsing will fail for combined conditions, e.g. Sa-Su AND weight>7
|
|
|
|
// http://wiki.openstreetmap.org/wiki/Conditional_restrictions#Combined_conditions:_AND
|
|
|
|
|
2017-08-01 11:18:12 -04:00
|
|
|
return osrm::util::CheckOpeningHours(conditions, *local_time);
|
2017-05-11 06:13:52 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<std::uint64_t>
|
2017-08-01 11:18:12 -04:00
|
|
|
updateConditionalTurns(std::vector<TurnPenalty> &turn_weight_penalties,
|
|
|
|
const std::vector<extractor::ConditionalTurnPenalty> &conditional_turns,
|
2017-05-11 06:13:52 -04:00
|
|
|
Timezoner time_zone_handler)
|
|
|
|
{
|
|
|
|
std::vector<std::uint64_t> updated_turns;
|
|
|
|
if (conditional_turns.size() == 0)
|
|
|
|
return updated_turns;
|
|
|
|
|
2017-08-01 11:18:12 -04:00
|
|
|
for (const auto &penalty : conditional_turns)
|
2017-05-11 06:13:52 -04:00
|
|
|
{
|
2017-08-01 11:18:12 -04:00
|
|
|
if (IsRestrictionValid(time_zone_handler, penalty))
|
2017-05-11 06:13:52 -04:00
|
|
|
{
|
2017-08-01 11:18:12 -04:00
|
|
|
turn_weight_penalties[penalty.turn_offset] = INVALID_TURN_PENALTY;
|
|
|
|
updated_turns.push_back(penalty.turn_offset);
|
2017-05-11 06:13:52 -04:00
|
|
|
}
|
|
|
|
}
|
2017-03-14 19:39:52 -04:00
|
|
|
return updated_turns;
|
2017-03-14 18:54:57 -04:00
|
|
|
}
|
2020-11-26 10:21:39 -05:00
|
|
|
} // namespace
|
2017-03-10 20:07:52 -05:00
|
|
|
|
2017-03-07 18:30:49 -05:00
|
|
|
EdgeID
|
|
|
|
Updater::LoadAndUpdateEdgeExpandedGraph(std::vector<extractor::EdgeBasedEdge> &edge_based_edge_list,
|
2018-02-01 10:00:15 -05:00
|
|
|
std::vector<EdgeWeight> &node_weights,
|
|
|
|
std::uint32_t &connectivity_checksum) const
|
2018-04-22 14:05:11 -04:00
|
|
|
{
|
|
|
|
std::vector<EdgeDuration> node_durations(node_weights.size());
|
|
|
|
return LoadAndUpdateEdgeExpandedGraph(
|
|
|
|
edge_based_edge_list, node_weights, node_durations, connectivity_checksum);
|
|
|
|
}
|
|
|
|
|
|
|
|
EdgeID
|
|
|
|
Updater::LoadAndUpdateEdgeExpandedGraph(std::vector<extractor::EdgeBasedEdge> &edge_based_edge_list,
|
|
|
|
std::vector<EdgeWeight> &node_weights,
|
|
|
|
std::vector<EdgeDuration> &node_durations,
|
|
|
|
std::uint32_t &connectivity_checksum) const
|
2017-03-07 18:30:49 -05:00
|
|
|
{
|
2017-03-10 20:20:22 -05:00
|
|
|
TIMER_START(load_edges);
|
|
|
|
|
2017-09-25 09:37:11 -04:00
|
|
|
EdgeID number_of_edge_based_nodes = 0;
|
2017-05-15 17:49:02 -04:00
|
|
|
std::vector<util::Coordinate> coordinates;
|
2017-05-11 06:13:52 -04:00
|
|
|
extractor::PackedOSMIDs osm_node_ids;
|
2017-03-07 18:30:49 -05:00
|
|
|
|
2018-04-22 14:05:11 -04:00
|
|
|
extractor::files::readEdgeBasedNodeWeightsDurations(
|
|
|
|
config.GetPath(".osrm.enw"), node_weights, node_durations);
|
2018-04-22 02:34:31 -04:00
|
|
|
|
2018-02-01 10:00:15 -05:00
|
|
|
extractor::files::readEdgeBasedGraph(config.GetPath(".osrm.ebg"),
|
|
|
|
number_of_edge_based_nodes,
|
|
|
|
edge_based_edge_list,
|
|
|
|
connectivity_checksum);
|
2017-06-16 04:45:24 -04:00
|
|
|
extractor::files::readNodes(config.GetPath(".osrm.nbg_nodes"), coordinates, osm_node_ids);
|
2017-03-07 18:30:49 -05:00
|
|
|
|
2017-05-11 06:13:52 -04:00
|
|
|
const bool update_conditional_turns =
|
2017-06-16 04:45:24 -04:00
|
|
|
!config.GetPath(".osrm.restrictions").empty() && config.valid_now;
|
2017-03-07 18:30:49 -05:00
|
|
|
const bool update_edge_weights = !config.segment_speed_lookup_paths.empty();
|
|
|
|
const bool update_turn_penalties = !config.turn_penalty_lookup_paths.empty();
|
|
|
|
|
2017-05-11 06:13:52 -04:00
|
|
|
if (!update_edge_weights && !update_turn_penalties && !update_conditional_turns)
|
2017-03-07 18:30:49 -05:00
|
|
|
{
|
2017-03-14 21:34:27 -04:00
|
|
|
saveDatasourcesNames(config);
|
2017-09-25 09:37:11 -04:00
|
|
|
return number_of_edge_based_nodes;
|
2017-03-07 18:30:49 -05:00
|
|
|
}
|
|
|
|
|
2017-03-14 21:34:27 -04:00
|
|
|
if (config.segment_speed_lookup_paths.size() + config.turn_penalty_lookup_paths.size() > 255)
|
|
|
|
throw util::exception("Limit of 255 segment speed and turn penalty files each reached" +
|
|
|
|
SOURCE_REF);
|
2017-03-07 18:30:49 -05:00
|
|
|
|
2017-04-25 05:36:34 -04:00
|
|
|
extractor::EdgeBasedNodeDataContainer node_data;
|
2017-03-14 12:04:38 -04:00
|
|
|
extractor::SegmentDataContainer segment_data;
|
2017-04-01 21:00:03 -04:00
|
|
|
extractor::ProfileProperties profile_properties;
|
2017-03-07 18:30:49 -05:00
|
|
|
std::vector<TurnPenalty> turn_weight_penalties;
|
|
|
|
std::vector<TurnPenalty> turn_duration_penalties;
|
2017-05-11 06:13:52 -04:00
|
|
|
if (update_edge_weights || update_turn_penalties || update_conditional_turns)
|
2017-03-14 18:54:57 -04:00
|
|
|
{
|
2018-03-19 11:57:57 -04:00
|
|
|
tbb::parallel_invoke(
|
|
|
|
[&] {
|
|
|
|
extractor::files::readSegmentData(config.GetPath(".osrm.geometry"), segment_data);
|
|
|
|
},
|
|
|
|
[&] { extractor::files::readNodeData(config.GetPath(".osrm.ebg_nodes"), node_data); },
|
|
|
|
|
|
|
|
[&] {
|
|
|
|
extractor::files::readTurnWeightPenalty(
|
|
|
|
config.GetPath(".osrm.turn_weight_penalties"), turn_weight_penalties);
|
|
|
|
},
|
|
|
|
[&] {
|
|
|
|
extractor::files::readTurnDurationPenalty(
|
|
|
|
config.GetPath(".osrm.turn_duration_penalties"), turn_duration_penalties);
|
|
|
|
},
|
|
|
|
[&] {
|
|
|
|
extractor::files::readProfileProperties(config.GetPath(".osrm.properties"),
|
|
|
|
profile_properties);
|
|
|
|
});
|
2017-03-14 19:39:52 -04:00
|
|
|
}
|
|
|
|
|
2017-08-01 11:18:12 -04:00
|
|
|
std::vector<extractor::ConditionalTurnPenalty> conditional_turns;
|
2017-05-11 06:13:52 -04:00
|
|
|
if (update_conditional_turns)
|
|
|
|
{
|
2018-03-19 19:31:49 -04:00
|
|
|
extractor::files::readConditionalRestrictions(config.GetPath(".osrm.restrictions"),
|
|
|
|
conditional_turns);
|
2017-05-11 06:13:52 -04:00
|
|
|
}
|
|
|
|
|
2017-03-14 19:39:52 -04:00
|
|
|
tbb::concurrent_vector<GeometryID> updated_segments;
|
|
|
|
if (update_edge_weights)
|
|
|
|
{
|
|
|
|
auto segment_speed_lookup = csv::readSegmentValues(config.segment_speed_lookup_paths);
|
|
|
|
|
|
|
|
TIMER_START(segment);
|
2017-05-11 06:13:52 -04:00
|
|
|
updated_segments = updateSegmentData(config,
|
|
|
|
profile_properties,
|
|
|
|
segment_speed_lookup,
|
|
|
|
segment_data,
|
2017-05-15 17:49:02 -04:00
|
|
|
coordinates,
|
2017-05-11 06:13:52 -04:00
|
|
|
osm_node_ids);
|
2017-03-14 19:39:52 -04:00
|
|
|
// Now save out the updated compressed geometries
|
2017-06-16 04:45:24 -04:00
|
|
|
extractor::files::writeSegmentData(config.GetPath(".osrm.geometry"), segment_data);
|
2017-03-14 19:39:52 -04:00
|
|
|
TIMER_STOP(segment);
|
|
|
|
util::Log() << "Updating segment data took " << TIMER_MSEC(segment) << "ms.";
|
|
|
|
}
|
|
|
|
|
2017-05-11 06:13:52 -04:00
|
|
|
auto turn_penalty_lookup = csv::readTurnValues(config.turn_penalty_lookup_paths);
|
2017-03-14 19:39:52 -04:00
|
|
|
if (update_turn_penalties)
|
|
|
|
{
|
2017-03-14 21:03:55 -04:00
|
|
|
auto updated_turn_penalties = updateTurnPenalties(config,
|
|
|
|
profile_properties,
|
|
|
|
turn_penalty_lookup,
|
|
|
|
turn_weight_penalties,
|
2017-05-11 06:13:52 -04:00
|
|
|
turn_duration_penalties,
|
|
|
|
osm_node_ids);
|
|
|
|
const auto offset = updated_segments.size();
|
|
|
|
updated_segments.resize(offset + updated_turn_penalties.size());
|
|
|
|
// we need to re-compute all edges that have updated turn penalties.
|
|
|
|
// this marks it for re-computation
|
|
|
|
std::transform(updated_turn_penalties.begin(),
|
|
|
|
updated_turn_penalties.end(),
|
|
|
|
updated_segments.begin() + offset,
|
|
|
|
[&node_data, &edge_based_edge_list](const std::uint64_t turn_id) {
|
|
|
|
const auto node_id = edge_based_edge_list[turn_id].source;
|
|
|
|
return node_data.GetGeometryID(node_id);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (update_conditional_turns)
|
|
|
|
{
|
|
|
|
// initialize instance of class that handles time zone resolution
|
|
|
|
if (config.valid_now <= 0)
|
|
|
|
{
|
|
|
|
util::Log(logERROR) << "Given UTC time is invalid: " << config.valid_now;
|
|
|
|
throw;
|
|
|
|
}
|
|
|
|
const Timezoner time_zone_handler = Timezoner(config.tz_file_path, config.valid_now);
|
|
|
|
|
2017-08-01 11:18:12 -04:00
|
|
|
auto updated_turn_penalties =
|
|
|
|
updateConditionalTurns(turn_weight_penalties, conditional_turns, time_zone_handler);
|
2017-03-16 17:47:27 -04:00
|
|
|
const auto offset = updated_segments.size();
|
|
|
|
updated_segments.resize(offset + updated_turn_penalties.size());
|
2017-03-14 21:03:55 -04:00
|
|
|
// we need to re-compute all edges that have updated turn penalties.
|
|
|
|
// this marks it for re-computation
|
2017-04-25 05:36:34 -04:00
|
|
|
std::transform(updated_turn_penalties.begin(),
|
|
|
|
updated_turn_penalties.end(),
|
|
|
|
updated_segments.begin() + offset,
|
2017-05-03 10:16:29 -04:00
|
|
|
[&node_data, &edge_based_edge_list](const std::uint64_t turn_id) {
|
|
|
|
const auto node_id = edge_based_edge_list[turn_id].source;
|
2017-04-25 05:36:34 -04:00
|
|
|
return node_data.GetGeometryID(node_id);
|
|
|
|
});
|
2017-03-14 18:54:57 -04:00
|
|
|
}
|
2017-03-07 18:30:49 -05:00
|
|
|
|
2017-03-14 21:03:55 -04:00
|
|
|
tbb::parallel_sort(updated_segments.begin(),
|
|
|
|
updated_segments.end(),
|
|
|
|
[](const GeometryID lhs, const GeometryID rhs) {
|
|
|
|
return std::tie(lhs.id, lhs.forward) < std::tie(rhs.id, rhs.forward);
|
|
|
|
});
|
|
|
|
|
|
|
|
using WeightAndDuration = std::tuple<EdgeWeight, EdgeWeight>;
|
|
|
|
const auto compute_new_weight_and_duration =
|
|
|
|
[&](const GeometryID geometry_id) -> WeightAndDuration {
|
|
|
|
EdgeWeight new_weight = 0;
|
|
|
|
EdgeWeight new_duration = 0;
|
|
|
|
if (geometry_id.forward)
|
|
|
|
{
|
|
|
|
const auto weights = segment_data.GetForwardWeights(geometry_id.id);
|
|
|
|
for (const auto weight : weights)
|
|
|
|
{
|
2017-05-10 19:04:09 -04:00
|
|
|
if (weight == INVALID_SEGMENT_WEIGHT)
|
2017-03-14 21:03:55 -04:00
|
|
|
{
|
|
|
|
new_weight = INVALID_EDGE_WEIGHT;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
new_weight += weight;
|
|
|
|
}
|
|
|
|
const auto durations = segment_data.GetForwardDurations(geometry_id.id);
|
2022-06-27 19:14:28 -04:00
|
|
|
// NOLINTNEXTLINE(bugprone-fold-init-type)
|
2017-03-16 17:47:27 -04:00
|
|
|
new_duration = std::accumulate(durations.begin(), durations.end(), EdgeWeight{0});
|
2017-03-14 21:03:55 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
const auto weights = segment_data.GetReverseWeights(geometry_id.id);
|
|
|
|
for (const auto weight : weights)
|
|
|
|
{
|
2017-05-10 19:04:09 -04:00
|
|
|
if (weight == INVALID_SEGMENT_WEIGHT)
|
2017-03-14 21:03:55 -04:00
|
|
|
{
|
|
|
|
new_weight = INVALID_EDGE_WEIGHT;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
new_weight += weight;
|
|
|
|
}
|
|
|
|
const auto durations = segment_data.GetReverseDurations(geometry_id.id);
|
2022-06-27 19:14:28 -04:00
|
|
|
// NOLINTNEXTLINE(bugprone-fold-init-type)
|
2017-03-16 17:47:27 -04:00
|
|
|
new_duration = std::accumulate(durations.begin(), durations.end(), EdgeWeight{0});
|
2017-03-14 21:03:55 -04:00
|
|
|
}
|
|
|
|
return std::make_tuple(new_weight, new_duration);
|
|
|
|
};
|
|
|
|
|
|
|
|
std::vector<WeightAndDuration> accumulated_segment_data(updated_segments.size());
|
|
|
|
tbb::parallel_for(tbb::blocked_range<std::size_t>(0, updated_segments.size()),
|
2017-03-16 17:47:27 -04:00
|
|
|
[&](const auto &range) {
|
2017-03-14 21:03:55 -04:00
|
|
|
for (auto index = range.begin(); index < range.end(); ++index)
|
|
|
|
{
|
|
|
|
accumulated_segment_data[index] =
|
|
|
|
compute_new_weight_and_duration(updated_segments[index]);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2017-03-14 21:34:27 -04:00
|
|
|
const auto update_edge = [&](extractor::EdgeBasedEdge &edge) {
|
2017-05-03 10:16:29 -04:00
|
|
|
const auto node_id = edge.source;
|
2017-04-25 05:36:34 -04:00
|
|
|
const auto geometry_id = node_data.GetGeometryID(node_id);
|
2017-03-14 21:34:27 -04:00
|
|
|
auto updated_iter = std::lower_bound(updated_segments.begin(),
|
|
|
|
updated_segments.end(),
|
|
|
|
geometry_id,
|
|
|
|
[](const GeometryID lhs, const GeometryID rhs) {
|
|
|
|
return std::tie(lhs.id, lhs.forward) <
|
|
|
|
std::tie(rhs.id, rhs.forward);
|
|
|
|
});
|
|
|
|
if (updated_iter != updated_segments.end() && updated_iter->id == geometry_id.id &&
|
|
|
|
updated_iter->forward == geometry_id.forward)
|
2017-03-07 18:30:49 -05:00
|
|
|
{
|
2017-03-14 21:34:27 -04:00
|
|
|
// Find a segment with zero speed and simultaneously compute the new edge
|
|
|
|
// weight
|
|
|
|
EdgeWeight new_weight;
|
|
|
|
EdgeWeight new_duration;
|
|
|
|
std::tie(new_weight, new_duration) =
|
|
|
|
accumulated_segment_data[updated_iter - updated_segments.begin()];
|
|
|
|
|
|
|
|
// Update the node-weight cache. This is the weight of the edge-based-node
|
2018-04-23 04:00:30 -04:00
|
|
|
// only, it doesn't include the turn. We may visit the same node multiple times,
|
|
|
|
// but we should always assign the same value here.
|
|
|
|
BOOST_ASSERT(edge.source < node_weights.size());
|
|
|
|
node_weights[edge.source] =
|
|
|
|
node_weights[edge.source] & 0x80000000 ? new_weight | 0x80000000 : new_weight;
|
2018-04-22 14:05:11 -04:00
|
|
|
node_durations[edge.source] = new_duration;
|
2017-03-14 21:34:27 -04:00
|
|
|
|
|
|
|
// We found a zero-speed edge, so we'll skip this whole edge-based-edge
|
|
|
|
// which
|
|
|
|
// effectively removes it from the routing network.
|
|
|
|
if (new_weight == INVALID_EDGE_WEIGHT)
|
2017-03-14 16:48:44 -04:00
|
|
|
{
|
2017-03-14 21:34:27 -04:00
|
|
|
edge.data.weight = INVALID_EDGE_WEIGHT;
|
|
|
|
return;
|
|
|
|
}
|
2017-03-07 18:30:49 -05:00
|
|
|
|
2017-03-14 21:34:27 -04:00
|
|
|
// Get the turn penalty and update to the new value if required
|
2017-03-10 04:57:07 -05:00
|
|
|
auto turn_weight_penalty = turn_weight_penalties[edge.data.turn_id];
|
|
|
|
auto turn_duration_penalty = turn_duration_penalties[edge.data.turn_id];
|
2017-03-14 21:34:27 -04:00
|
|
|
const auto num_nodes = segment_data.GetForwardGeometry(geometry_id.id).size();
|
|
|
|
const auto weight_min_value = static_cast<EdgeWeight>(num_nodes);
|
|
|
|
if (turn_weight_penalty + new_weight < weight_min_value)
|
|
|
|
{
|
|
|
|
if (turn_weight_penalty < 0)
|
2017-03-14 17:20:32 -04:00
|
|
|
{
|
2020-11-26 10:21:39 -05:00
|
|
|
util::Log(logWARNING)
|
|
|
|
<< "turn penalty " << turn_weight_penalty
|
|
|
|
<< " is too negative: clamping turn weight to " << weight_min_value;
|
2017-03-14 21:34:27 -04:00
|
|
|
turn_weight_penalty = weight_min_value - new_weight;
|
2017-03-10 04:57:07 -05:00
|
|
|
turn_weight_penalties[edge.data.turn_id] = turn_weight_penalty;
|
2017-03-14 21:34:27 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
new_weight = weight_min_value;
|
2017-03-14 17:20:32 -04:00
|
|
|
}
|
2017-03-07 18:30:49 -05:00
|
|
|
}
|
2017-03-14 21:34:27 -04:00
|
|
|
|
|
|
|
// Update edge weight
|
|
|
|
edge.data.weight = new_weight + turn_weight_penalty;
|
|
|
|
edge.data.duration = new_duration + turn_duration_penalty;
|
2017-03-07 18:30:49 -05:00
|
|
|
}
|
2017-03-14 21:34:27 -04:00
|
|
|
};
|
2017-03-07 18:30:49 -05:00
|
|
|
|
2017-03-14 21:34:27 -04:00
|
|
|
if (updated_segments.size() > 0)
|
|
|
|
{
|
|
|
|
tbb::parallel_for(tbb::blocked_range<std::size_t>(0, edge_based_edge_list.size()),
|
2017-03-16 17:47:27 -04:00
|
|
|
[&](const auto &range) {
|
2017-03-14 21:34:27 -04:00
|
|
|
for (auto index = range.begin(); index < range.end(); ++index)
|
|
|
|
{
|
|
|
|
update_edge(edge_based_edge_list[index]);
|
|
|
|
}
|
|
|
|
});
|
2017-03-07 18:30:49 -05:00
|
|
|
}
|
|
|
|
|
2017-05-31 16:59:50 -04:00
|
|
|
if (update_turn_penalties || update_conditional_turns)
|
2017-03-07 18:30:49 -05:00
|
|
|
{
|
|
|
|
tbb::parallel_invoke(
|
2017-06-16 04:45:24 -04:00
|
|
|
[&] {
|
2018-03-19 11:57:57 -04:00
|
|
|
extractor::files::writeTurnWeightPenalty(
|
|
|
|
config.GetPath(".osrm.turn_weight_penalties"), turn_weight_penalties);
|
2017-06-16 04:45:24 -04:00
|
|
|
},
|
|
|
|
[&] {
|
2018-03-19 11:57:57 -04:00
|
|
|
extractor::files::writeTurnDurationPenalty(
|
|
|
|
config.GetPath(".osrm.turn_duration_penalties"), turn_duration_penalties);
|
2017-06-16 04:45:24 -04:00
|
|
|
});
|
2017-03-07 18:30:49 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#if !defined(NDEBUG)
|
|
|
|
if (config.turn_penalty_lookup_paths.empty())
|
|
|
|
{ // don't check weights consistency with turn updates that can break assertion
|
|
|
|
// condition with turn weight penalties negative updates
|
2017-03-10 20:07:52 -05:00
|
|
|
checkWeightsConsistency(config, edge_based_edge_list);
|
2017-03-07 18:30:49 -05:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-03-10 20:20:22 -05:00
|
|
|
saveDatasourcesNames(config);
|
|
|
|
|
|
|
|
TIMER_STOP(load_edges);
|
|
|
|
util::Log() << "Done reading edges in " << TIMER_MSEC(load_edges) << "ms.";
|
2017-09-25 09:37:11 -04:00
|
|
|
return number_of_edge_based_nodes;
|
2017-03-07 18:30:49 -05:00
|
|
|
}
|
2020-11-26 10:21:39 -05:00
|
|
|
} // namespace updater
|
|
|
|
} // namespace osrm
|