From c3d0efda936b94b0f05e69a78e00695c6bc167fe Mon Sep 17 00:00:00 2001 From: MichalPP Date: Sat, 12 May 2018 13:33:08 +0200 Subject: [PATCH 01/26] change barrier_whitelist to barrier_blacklist --- profiles/bicycle.lua | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/profiles/bicycle.lua b/profiles/bicycle.lua index f08bcebe26d..0cd3a62c9be 100644 --- a/profiles/bicycle.lua +++ b/profiles/bicycle.lua @@ -38,20 +38,10 @@ function setup() mode.pushing_bike }, - barrier_whitelist = Set { - 'sump_buster', - 'bus_trap', - 'cycle_barrier', - 'bollard', - 'entrance', - 'cattle_grid', - 'border_control', - 'toll_booth', - 'sally_port', - 'gate', - 'lift_gate', - 'no', - 'block' + barrier_blacklist = Set { + 'yes', + 'wall', + 'fence' }, access_tag_whitelist = Set { @@ -245,7 +235,7 @@ function process_node(profile, node, result) else local barrier = node:get_value_by_key("barrier") if barrier and "" ~= barrier then - if not profile.barrier_whitelist[barrier] then + if profile.barrier_blacklist[barrier] then result.barrier = true end end From 8dd8ee1fc2c86b9c7c2cbe97128a12ed529155df Mon Sep 17 00:00:00 2001 From: MichalPP Date: Sat, 19 May 2018 10:33:55 +0200 Subject: [PATCH 02/26] blacklisting barriers allow routing blacklisting barriers allow routing over barrier=some_tag --- features/bicycle/barrier.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/bicycle/barrier.feature b/features/bicycle/barrier.feature index a23eee54c9b..ae4ab579ce8 100644 --- a/features/bicycle/barrier.feature +++ b/features/bicycle/barrier.feature @@ -19,7 +19,7 @@ Feature: Barriers | entrance | x | | wall | | | fence | | - | some_tag | | + | some_tag | x | | block | x | Scenario: Bike - Access tag trumphs barriers From 918e794d6a5a6211851ab134fdaba7d0cf9e7d5e Mon Sep 17 00:00:00 2001 From: MichalPP Date: Sat, 12 May 2018 13:30:25 +0200 Subject: [PATCH 03/26] change barrier_whitelist to barrier blacklist change barrier_whitelist to barrier blacklist in foot profile fix #5067 and #3890 and #4823 --- profiles/foot.lua | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/profiles/foot.lua b/profiles/foot.lua index f0527337bf8..ea24706c86c 100644 --- a/profiles/foot.lua +++ b/profiles/foot.lua @@ -24,19 +24,10 @@ function setup() default_speed = walking_speed, oneway_handling = 'specific', -- respect 'oneway:foot' but not 'oneway' - barrier_whitelist = Set { - 'cycle_barrier', - 'bollard', - 'entrance', - 'cattle_grid', - 'border_control', - 'toll_booth', - 'sally_port', - 'gate', - 'lift_gate', - 'no', - 'kerb', - 'block' + barrier_blacklist = Set { + 'yes', + 'wall', + 'fence' }, access_tag_whitelist = Set { @@ -157,7 +148,7 @@ function process_node(profile, node, result) local bollard = node:get_value_by_key("bollard") local rising_bollard = bollard and "rising" == bollard - if not profile.barrier_whitelist[barrier] and not rising_bollard then + if profile.barrier_blacklist[barrier] and not rising_bollard then result.barrier = true end end From 06699132ebdf0711e624206e3ca1967682e8bbaf Mon Sep 17 00:00:00 2001 From: MichalPP Date: Tue, 29 May 2018 15:31:03 +0200 Subject: [PATCH 04/26] allow routing over barrier=some_tag --- features/foot/barrier.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/foot/barrier.feature b/features/foot/barrier.feature index df95390f5a2..f8cffdd79ed 100644 --- a/features/foot/barrier.feature +++ b/features/foot/barrier.feature @@ -19,7 +19,7 @@ Feature: Barriers | entrance | x | | wall | | | fence | | - | some_tag | | + | some_tag | x | | block | x | Scenario: Foot - Access tag trumphs barriers From e5d8319c43b454642079f66b930ac73803840e2b Mon Sep 17 00:00:00 2001 From: Matthias Gilch Date: Sat, 2 Jun 2018 14:33:49 +0200 Subject: [PATCH 05/26] Removed unused variable The variable name_data_mutex is declared in a block but never used within this block. So I've removed the variable. --- src/extractor/extraction_containers.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/extractor/extraction_containers.cpp b/src/extractor/extraction_containers.cpp index d5c31d53414..6f5668bb3c7 100644 --- a/src/extractor/extraction_containers.cpp +++ b/src/extractor/extraction_containers.cpp @@ -430,7 +430,6 @@ void ExtractionContainers::PrepareEdges(ScriptingEnvironment &scripting_environm util::UnbufferedLog log; log << "Sorting edges by renumbered start ... "; TIMER_START(sort_edges_by_renumbered_start); - std::mutex name_data_mutex; tbb::parallel_sort(all_edges_list.begin(), all_edges_list.end(), CmpEdgeByInternalSourceTargetAndName{ From 1628a3c4d5349a29b28b83624235ff3b06ab411d Mon Sep 17 00:00:00 2001 From: Antoine Giret Date: Thu, 7 Jun 2018 11:39:43 +0200 Subject: [PATCH 06/26] Update profiles.md --- docs/profiles.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/profiles.md b/docs/profiles.md index 248e9cb526c..8b7ef7cf99d 100644 --- a/docs/profiles.md +++ b/docs/profiles.md @@ -138,7 +138,7 @@ Given an OpenStreetMap way, the `process_way` function will either return nothin Argument | Description ---------|------------------------------------------------------- profile | The configuration table you returned in `setup`. -node | The input way to process (read-only). +way | The input way to process (read-only). result | The output that you will modify. relations| Storage of relations to access relations, where `way` is a member. From 82b5648c97edf1d2edec7aecebc35aa8a8033c82 Mon Sep 17 00:00:00 2001 From: Michael Krasnyk Date: Thu, 21 Jun 2018 14:02:06 +0200 Subject: [PATCH 07/26] Don't collapse segregated intersections at roundabout exits, #5114 --- CHANGELOG.md | 5 +++++ src/engine/guidance/collapse_turns.cpp | 1 + 2 files changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 52b1c2a1dfd..64f392aa5dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,9 @@ # UNRELEASED + - Changes from 5.18.0: + - Bugfixes: + - FIXED: collapsing of ExitRoundabout instructions [#5114](https://github.com/Project-OSRM/osrm-backend/issues/5114) + +# 5.18.0 - Changes from 5.17.0: - Features: - ADDED: `table` plugin now optionally returns `distance` matrix as part of response [#4990](https://github.com/Project-OSRM/osrm-backend/pull/4990) diff --git a/src/engine/guidance/collapse_turns.cpp b/src/engine/guidance/collapse_turns.cpp index 8bf6570d710..d6a40cec0ab 100644 --- a/src/engine/guidance/collapse_turns.cpp +++ b/src/engine/guidance/collapse_turns.cpp @@ -621,6 +621,7 @@ RouteSteps collapseSegregatedTurnInstructions(RouteSteps steps) // else if the current step is segregated and the next step is not segregated // and the next step is not a roundabout then combine with turn adjustment else if (curr_step->is_segregated && !next_step->is_segregated && + !hasRoundaboutType(curr_step->maneuver.instruction) && !hasRoundaboutType(next_step->maneuver.instruction)) { // Determine if u-turn From 3a7b377586a7019105c469b4c77158b956021bfd Mon Sep 17 00:00:00 2001 From: Antoine Giret Date: Thu, 7 Jun 2018 11:30:11 +0200 Subject: [PATCH 08/26] Update profiles.md --- docs/profiles.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/profiles.md b/docs/profiles.md index 8b7ef7cf99d..090c5c36bd5 100644 --- a/docs/profiles.md +++ b/docs/profiles.md @@ -199,7 +199,7 @@ source.lon | Read | Float | Co-ordinates of segment start source.lat | Read | Float | "" target.lon | Read | Float | Co-ordinates of segment end target.lat | Read | Float | "" -target.distance | Read | Float | Length of segment +distance | Read | Float | Length of segment weight | Read/write | Float | Routing weight for this segment duration | Read/write | Float | Duration for this segment From d2590989f5bf02a275ab944f77dfba42ae64b48d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Rodrigo?= Date: Fri, 6 Jul 2018 14:35:01 +0200 Subject: [PATCH 09/26] Default maxspeed for fr:rural is now 80km/h --- profiles/car.lua | 1 + taginfo.json | 1 + 2 files changed, 2 insertions(+) diff --git a/profiles/car.lua b/profiles/car.lua index 161a6466bae..ff508ee94da 100644 --- a/profiles/car.lua +++ b/profiles/car.lua @@ -276,6 +276,7 @@ function setup() ["de:rural"] = 100, ["de:motorway"] = 0, ["dk:rural"] = 80, + ["fr:rural"] = 80, ["gb:nsl_single"] = (60*1609)/1000, ["gb:nsl_dual"] = (70*1609)/1000, ["gb:motorway"] = (70*1609)/1000, diff --git a/taginfo.json b/taginfo.json index 3796bc67a60..0bb923ecf7d 100644 --- a/taginfo.json +++ b/taginfo.json @@ -159,6 +159,7 @@ {"key": "maxspeed", "value": "DE:rural"}, {"key": "maxspeed", "value": "DE:motorway"}, {"key": "maxspeed", "value": "DK:rural"}, + {"key": "maxspeed", "value": "FR:rural"}, {"key": "maxspeed", "value": "GB:nsl_single"}, {"key": "maxspeed", "value": "GB:nsl_dual"}, {"key": "maxspeed", "value": "GB:motorway"}, From 3088dd0342d32172a263019698feb50a3cb263e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Rodrigo?= Date: Wed, 6 Jun 2018 10:53:57 +0200 Subject: [PATCH 10/26] Better and flexible weight parsing in measure.lua --- profiles/lib/measure.lua | 37 ++++++++++++------------------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/profiles/lib/measure.lua b/profiles/lib/measure.lua index b433fbe9b09..88bbcbd7417 100644 --- a/profiles/lib/measure.lua +++ b/profiles/lib/measure.lua @@ -5,6 +5,7 @@ Measure = {} -- measurements conversion constants local inch_to_meters = 0.0254 local feet_to_inches = 12 +local pound_to_kilograms = 0.45359237 --- Parse string as a height in meters. --- according to http://wiki.openstreetmap.org/wiki/Key:maxheight @@ -25,33 +26,19 @@ function Measure.parse_value_meters(value) end end ---- according to http://wiki.openstreetmap.org/wiki/Map_Features/Units#Explicit_specifications -local tonns_parse_patterns = Sequence { - "%d+", - "%d+.%d+", - "%d+.%d+ ?t" -} - -local kg_parse_patterns = Sequence { - "%d+ ?kg" -} - ---- Parse weight value in kilograms +--- Parse weight value in kilograms. +--- according to https://wiki.openstreetmap.org/wiki/Key:maxweight function Measure.parse_value_kilograms(value) - -- try to parse kilograms - for i, templ in ipairs(kg_parse_patterns) do - m = string.match(value, templ) - if m then - return tonumber(m) - end - end - - -- try to parse tonns - for i, templ in ipairs(tonns_parse_patterns) do - m = string.match(value, templ) - if m then - return tonumber(m) * 1000 + local n = tonumber(value:gsub(",", "."):match("%d+%.?%d*")) + if n then + if string.match(value, "lbs") then + n = n * pound_to_kilograms + elseif string.match(value, "kg") then + -- n = n + else -- Default, metric tons + n = n * 1000 end + return n end end From 7ff68792d77afb14e0afcc4c657805fee34aaa06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Rodrigo?= Date: Wed, 6 Jun 2018 11:07:01 +0200 Subject: [PATCH 11/26] Add helper for maxlength into measure.lua --- profiles/lib/measure.lua | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/profiles/lib/measure.lua b/profiles/lib/measure.lua index 88bbcbd7417..6bcff08f8e9 100644 --- a/profiles/lib/measure.lua +++ b/profiles/lib/measure.lua @@ -70,7 +70,14 @@ function Measure.get_max_width(raw_value) end end ---- Get maxweight of specified way in kilogramms +--- Get maxlength of specified way in meters. +function Measure.get_max_length(raw_value) + if raw_value then + return Measure.parse_value_meters(raw_value) + end +end + +--- Get maxweight of specified way in kilogramms. function Measure.get_max_weight(raw_value) if raw_value then return Measure.parse_value_kilograms(raw_value) From f9289565848246c02ffaafbafe106e07a00b5261 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Rodrigo?= Date: Wed, 6 Jun 2018 13:50:48 +0200 Subject: [PATCH 12/26] Support maxlength and maxweight in car profile --- features/car/physical_limitation.feature | 19 ++++++++++++++ profiles/car.lua | 6 +++++ profiles/lib/way_handlers.lua | 32 ++++++++++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/features/car/physical_limitation.feature b/features/car/physical_limitation.feature index d65f40a19f0..43eef90f8e0 100644 --- a/features/car/physical_limitation.feature +++ b/features/car/physical_limitation.feature @@ -48,3 +48,22 @@ Feature: Car - Handle physical limitation | primary | | none | x | | primary | | no-sign | x | | primary | | unsigned | x | + + Scenario: Car - Limited by length + Then routability should be + | highway | maxlength | bothw | + | primary | | x | + | primary | 1 | | + | primary | 5 | x | + | primary | unsigned | x | + + Scenario: Car - Limited by weight + Then routability should be + | highway | maxweight | bothw | + | primary | | x | + | primary | 1 | | + | primary | 3.5 | x | + | primary | 35000 kg | x | + | primary | 8.9t | x | + | primary | 0.1 lbs | | + | primary | unsigned | x | diff --git a/profiles/car.lua b/profiles/car.lua index ff508ee94da..a73980d919c 100644 --- a/profiles/car.lua +++ b/profiles/car.lua @@ -42,6 +42,10 @@ function setup() vehicle_height = 2.5, -- in meters, 2.5m is the height of van vehicle_width = 1.9, -- in meters, ways with narrow tag are considered narrower than 2.2m + -- Size of the vehicle, to be limited mostly by legal restriction of the way + vehicle_length = 4.8, -- in meters, 4.8m is the length of large or familly car + vehicle_weight = 3500, -- in kilograms + -- a list of suffixes to suppress in name change instructions. The suffixes also include common substrings of each other suffix_list = { 'N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW', 'North', 'South', 'West', 'East', 'Nor', 'Sou', 'We', 'Ea' @@ -388,6 +392,8 @@ function process_way(profile, way, result, relations) WayHandlers.avoid_ways, WayHandlers.handle_height, WayHandlers.handle_width, + WayHandlers.handle_length, + WayHandlers.handle_weight, -- determine access status by checking our hierarchy of -- access tags, e.g: motorcar, motor_vehicle, vehicle diff --git a/profiles/lib/way_handlers.lua b/profiles/lib/way_handlers.lua index ef9fa88e8c0..265929d733c 100644 --- a/profiles/lib/way_handlers.lua +++ b/profiles/lib/way_handlers.lua @@ -511,6 +511,38 @@ function WayHandlers.handle_width(profile,way,result,data) end end +-- handle maxweight tags +function WayHandlers.handle_weight(profile,way,result,data) + local keys = Sequence { 'maxweight' } + local forward, backward = Tags.get_forward_backward_by_set(way,data,keys) + forward = Measure.get_max_weight(forward) + backward = Measure.get_max_weight(backward) + + if forward and forward < profile.vehicle_weight then + result.forward_mode = mode.inaccessible + end + + if backward and backward < profile.vehicle_weight then + result.backward_mode = mode.inaccessible + end +end + +-- handle maxlength tags +function WayHandlers.handle_length(profile,way,result,data) + local keys = Sequence { 'maxlength' } + local forward, backward = Tags.get_forward_backward_by_set(way,data,keys) + forward = Measure.get_max_length(forward) + backward = Measure.get_max_length(backward) + + if forward and forward < profile.vehicle_length then + result.forward_mode = mode.inaccessible + end + + if backward and backward < profile.vehicle_length then + result.backward_mode = mode.inaccessible + end +end + -- handle oneways tags function WayHandlers.oneway(profile,way,result,data) if not profile.oneway_handling then From a649a8a5cfb0b00d02f2bf50bf6c1db387cb9f2e Mon Sep 17 00:00:00 2001 From: Patrick Niklaus Date: Thu, 26 Apr 2018 22:26:01 +0000 Subject: [PATCH 13/26] Use FCC algorithm for map matching distance calculation --- .../routing_algorithms/routing_base.hpp | 44 +++---------------- include/util/coordinate_calculation.hpp | 3 -- src/util/coordinate_calculation.cpp | 9 +++- 3 files changed, 12 insertions(+), 44 deletions(-) diff --git a/include/engine/routing_algorithms/routing_base.hpp b/include/engine/routing_algorithms/routing_base.hpp index 0c0808a3f49..f1a89f195fc 100644 --- a/include/engine/routing_algorithms/routing_base.hpp +++ b/include/engine/routing_algorithms/routing_base.hpp @@ -323,53 +323,19 @@ void annotatePath(const FacadeT &facade, template double getPathDistance(const DataFacade &facade, - const std::vector unpacked_path, + const std::vector &unpacked_path, const PhantomNode &source_phantom, const PhantomNode &target_phantom) { - using util::coordinate_calculation::detail::DEGREE_TO_RAD; - using util::coordinate_calculation::detail::EARTH_RADIUS; - double distance = 0; - double prev_lat = - static_cast(util::toFloating(source_phantom.location.lat)) * DEGREE_TO_RAD; - double prev_lon = - static_cast(util::toFloating(source_phantom.location.lon)) * DEGREE_TO_RAD; - double prev_cos = std::cos(prev_lat); + auto prev_coordinate = source_phantom.location; for (const auto &p : unpacked_path) { const auto current_coordinate = facade.GetCoordinateOfNode(p.turn_via_node); - - const double current_lat = - static_cast(util::toFloating(current_coordinate.lat)) * DEGREE_TO_RAD; - const double current_lon = - static_cast(util::toFloating(current_coordinate.lon)) * DEGREE_TO_RAD; - const double current_cos = std::cos(current_lat); - - const double sin_dlon = std::sin((prev_lon - current_lon) / 2.0); - const double sin_dlat = std::sin((prev_lat - current_lat) / 2.0); - - const double aharv = sin_dlat * sin_dlat + prev_cos * current_cos * sin_dlon * sin_dlon; - const double charv = 2. * std::atan2(std::sqrt(aharv), std::sqrt(1.0 - aharv)); - distance += EARTH_RADIUS * charv; - - prev_lat = current_lat; - prev_lon = current_lon; - prev_cos = current_cos; + distance += util::coordinate_calculation::fccApproximateDistance(prev_coordinate, current_coordinate); + prev_coordinate = current_coordinate; } - - const double current_lat = - static_cast(util::toFloating(target_phantom.location.lat)) * DEGREE_TO_RAD; - const double current_lon = - static_cast(util::toFloating(target_phantom.location.lon)) * DEGREE_TO_RAD; - const double current_cos = std::cos(current_lat); - - const double sin_dlon = std::sin((prev_lon - current_lon) / 2.0); - const double sin_dlat = std::sin((prev_lat - current_lat) / 2.0); - - const double aharv = sin_dlat * sin_dlat + prev_cos * current_cos * sin_dlon * sin_dlon; - const double charv = 2. * std::atan2(std::sqrt(aharv), std::sqrt(1.0 - aharv)); - distance += EARTH_RADIUS * charv; + distance += util::coordinate_calculation::fccApproximateDistance(prev_coordinate, target_phantom.location); return distance; } diff --git a/include/util/coordinate_calculation.hpp b/include/util/coordinate_calculation.hpp index c946842a23e..884169e4cc3 100644 --- a/include/util/coordinate_calculation.hpp +++ b/include/util/coordinate_calculation.hpp @@ -23,9 +23,6 @@ namespace detail { const constexpr double DEGREE_TO_RAD = 0.017453292519943295769236907684886; const constexpr double RAD_TO_DEGREE = 1. / DEGREE_TO_RAD; -// earth radius varies between 6,356.750-6,378.135 km (3,949.901-3,963.189mi) -// The IUGG value for the equatorial radius is 6378.137 km (3963.19 miles) -const constexpr long double EARTH_RADIUS = 6372797.560856; inline double degToRad(const double degree) { diff --git a/src/util/coordinate_calculation.cpp b/src/util/coordinate_calculation.cpp index cb9adb10a9b..4303375ff12 100644 --- a/src/util/coordinate_calculation.cpp +++ b/src/util/coordinate_calculation.cpp @@ -22,6 +22,11 @@ namespace coordinate_calculation namespace { + +// earth radius varies between 6,356.750-6,378.135 km (3,949.901-3,963.189mi) +// The IUGG value for the equatorial radius is 6378.137 km (3963.19 miles) +const constexpr long double EARTH_RADIUS = 6372797.560856; + class CheapRulerContainer { public: @@ -112,7 +117,7 @@ double haversineDistance(const Coordinate coordinate_1, const Coordinate coordin const double aharv = std::pow(std::sin(dlat / 2.0), 2.0) + std::cos(dlat1) * std::cos(dlat2) * std::pow(std::sin(dlong / 2.), 2); const double charv = 2. * std::atan2(std::sqrt(aharv), std::sqrt(1.0 - aharv)); - return detail::EARTH_RADIUS * charv; + return EARTH_RADIUS * charv; } double greatCircleDistance(const Coordinate coordinate_1, const Coordinate coordinate_2) @@ -133,7 +138,7 @@ double greatCircleDistance(const Coordinate coordinate_1, const Coordinate coord const double x_value = (float_lon2 - float_lon1) * std::cos((float_lat1 + float_lat2) / 2.0); const double y_value = float_lat2 - float_lat1; - return std::hypot(x_value, y_value) * detail::EARTH_RADIUS; + return std::hypot(x_value, y_value) * EARTH_RADIUS; } double perpendicularDistance(const Coordinate segment_source, From 89fabc1b9c61545300223b364aa788ab61055721 Mon Sep 17 00:00:00 2001 From: Patrick Niklaus Date: Fri, 27 Apr 2018 05:00:59 +0000 Subject: [PATCH 14/26] Use distance functions from many to many --- .../routing_algorithms/routing_base.hpp | 22 ++---- .../routing_algorithms/routing_base_mld.hpp | 17 +++-- .../routing_algorithms/many_to_many_ch.cpp | 67 +------------------ .../routing_algorithms/routing_base.cpp | 66 ++++++++++++++++++ .../routing_algorithms/routing_base_ch.cpp | 33 +++++++-- 5 files changed, 111 insertions(+), 94 deletions(-) diff --git a/include/engine/routing_algorithms/routing_base.hpp b/include/engine/routing_algorithms/routing_base.hpp index f1a89f195fc..e00f5c4fabb 100644 --- a/include/engine/routing_algorithms/routing_base.hpp +++ b/include/engine/routing_algorithms/routing_base.hpp @@ -321,24 +321,10 @@ void annotatePath(const FacadeT &facade, } } -template -double getPathDistance(const DataFacade &facade, - const std::vector &unpacked_path, - const PhantomNode &source_phantom, - const PhantomNode &target_phantom) -{ - double distance = 0; - auto prev_coordinate = source_phantom.location; - for (const auto &p : unpacked_path) - { - const auto current_coordinate = facade.GetCoordinateOfNode(p.turn_via_node); - distance += util::coordinate_calculation::fccApproximateDistance(prev_coordinate, current_coordinate); - prev_coordinate = current_coordinate; - } - distance += util::coordinate_calculation::fccApproximateDistance(prev_coordinate, target_phantom.location); - - return distance; -} +void adjustPathDistanceToPhantomNodes(const std::vector &path, + const PhantomNode &source_phantom, + const PhantomNode &target_phantom, + EdgeDistance &distance); template InternalRouteResult extractRoute(const DataFacade &facade, diff --git a/include/engine/routing_algorithms/routing_base_mld.hpp b/include/engine/routing_algorithms/routing_base_mld.hpp index ce9b23d70a0..d893369f568 100644 --- a/include/engine/routing_algorithms/routing_base_mld.hpp +++ b/include/engine/routing_algorithms/routing_base_mld.hpp @@ -120,7 +120,7 @@ inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition, } return result; } -} +} // namespace // Heaps only record for each node its predecessor ("parent") on the shortest path. // For re-constructing the actual path we need to trace back all parent "pointers". @@ -680,11 +680,20 @@ double getNetworkDistance(SearchEngineData &engine_working_data, return std::numeric_limits::max(); } - std::vector unpacked_path; + EdgeDistance distance = 0; - annotatePath(facade, phantom_nodes, unpacked_nodes, unpacked_edges, unpacked_path); + if (!unpacked_nodes.empty()) + { + for (auto node_iter = unpacked_nodes.begin(); node_iter != std::prev(unpacked_nodes.end()); node_iter++) + { + distance += computeEdgeDistance(facade, *node_iter); + } + } + + adjustPathDistanceToPhantomNodes( + unpacked_nodes, phantom_nodes.source_phantom, phantom_nodes.target_phantom, distance); - return getPathDistance(facade, unpacked_path, source_phantom, target_phantom); + return distance / 10.; } } // namespace mld diff --git a/src/engine/routing_algorithms/many_to_many_ch.cpp b/src/engine/routing_algorithms/many_to_many_ch.cpp index 8ee02b5ec92..00449b9cbb1 100644 --- a/src/engine/routing_algorithms/many_to_many_ch.cpp +++ b/src/engine/routing_algorithms/many_to_many_ch.cpp @@ -240,74 +240,11 @@ void calculateDistances(typename SearchEngineData::ManyToManyQuer } if (!packed_leg.empty()) { - auto annotation = + EdgeDistance annotation = ch::calculateEBGNodeAnnotations(facade, packed_leg.begin(), packed_leg.end()); + adjustPathDistanceToPhantomNodes(packed_leg, source_phantom, target_phantom, annotation); distances_table[row_index * number_of_targets + column_index] = annotation; - - // check the direction of travel to figure out how to calculate the offset to/from - // the source/target - if (source_phantom.forward_segment_id.id == packed_leg.front()) - { - // ............ <-- calculateEGBAnnotation returns distance from 0 to 3 - // -->s <-- subtract offset to start at source - // ......... <-- want this distance as result - // entry 0---1---2---3--- <-- 3 is exit node - EdgeDistance offset = source_phantom.GetForwardDistance(); - distances_table[row_index * number_of_targets + column_index] -= offset; - } - else if (source_phantom.reverse_segment_id.id == packed_leg.front()) - { - // ............ <-- calculateEGBAnnotation returns distance from 0 to 3 - // s<------- <-- subtract offset to start at source - // ... <-- want this distance - // entry 0---1---2---3 <-- 3 is exit node - EdgeDistance offset = source_phantom.GetReverseDistance(); - distances_table[row_index * number_of_targets + column_index] -= offset; - } - if (target_phantom.forward_segment_id.id == packed_leg.back()) - { - // ............ <-- calculateEGBAnnotation returns distance from 0 to 3 - // ++>t <-- add offset to get to target - // ................ <-- want this distance as result - // entry 0---1---2---3--- <-- 3 is exit node - EdgeDistance offset = target_phantom.GetForwardDistance(); - distances_table[row_index * number_of_targets + column_index] += offset; - } - else if (target_phantom.reverse_segment_id.id == packed_leg.back()) - { - // ............ <-- calculateEGBAnnotation returns distance from 0 to 3 - // <++t <-- add offset to get from target - // ................ <-- want this distance as result - // entry 0---1---2---3--- <-- 3 is exit node - EdgeDistance offset = target_phantom.GetReverseDistance(); - distances_table[row_index * number_of_targets + column_index] += offset; - } - } - else - { - // there is no shortcut to unpack. source and target are on the same EBG Node. - // if the offset of the target is greater than the offset of the source, subtract it - if (target_phantom.GetForwardDistance() > source_phantom.GetForwardDistance()) - { - // --------->t <-- offsets - // ->s <-- subtract source offset from target offset - // ......... <-- want this distance as result - // entry 0---1---2---3--- <-- 3 is exit node - EdgeDistance offset = - target_phantom.GetForwardDistance() - source_phantom.GetForwardDistance(); - distances_table[row_index * number_of_targets + column_index] = offset; - } - else - { - // s<--- <-- offsets - // t<--------- <-- subtract source offset from target offset - // ...... <-- want this distance as result - // entry 0---1---2---3--- <-- 3 is exit node - EdgeDistance offset = - target_phantom.GetReverseDistance() - source_phantom.GetReverseDistance(); - distances_table[row_index * number_of_targets + column_index] = offset; - } } packed_leg.clear(); } diff --git a/src/engine/routing_algorithms/routing_base.cpp b/src/engine/routing_algorithms/routing_base.cpp index fb01472bbaa..236e957fea1 100644 --- a/src/engine/routing_algorithms/routing_base.cpp +++ b/src/engine/routing_algorithms/routing_base.cpp @@ -33,6 +33,72 @@ bool needsLoopBackwards(const PhantomNodes &phantoms) return needsLoopBackwards(phantoms.source_phantom, phantoms.target_phantom); } +void adjustPathDistanceToPhantomNodes(const std::vector &path, + const PhantomNode &source_phantom, + const PhantomNode &target_phantom, + EdgeDistance &distance) +{ + if (!path.empty()) + { + + // check the direction of travel to figure out how to calculate the offset to/from + // the source/target + if (source_phantom.forward_segment_id.id == path.front()) + { + // ............ <-- calculateEGBAnnotation returns distance from 0 to 3 + // -->s <-- subtract offset to start at source + // ......... <-- want this distance as result + // entry 0---1---2---3--- <-- 3 is exit node + distance -= source_phantom.GetForwardDistance(); + } + else if (source_phantom.reverse_segment_id.id == path.front()) + { + // ............ <-- calculateEGBAnnotation returns distance from 0 to 3 + // s<------- <-- subtract offset to start at source + // ... <-- want this distance + // entry 0---1---2---3 <-- 3 is exit node + distance -= source_phantom.GetReverseDistance(); + } + if (target_phantom.forward_segment_id.id == path.back()) + { + // ............ <-- calculateEGBAnnotation returns distance from 0 to 3 + // ++>t <-- add offset to get to target + // ................ <-- want this distance as result + // entry 0---1---2---3--- <-- 3 is exit node + distance += target_phantom.GetForwardDistance(); + } + else if (target_phantom.reverse_segment_id.id == path.back()) + { + // ............ <-- calculateEGBAnnotation returns distance from 0 to 3 + // <++t <-- add offset to get from target + // ................ <-- want this distance as result + // entry 0---1---2---3--- <-- 3 is exit node + distance += target_phantom.GetReverseDistance(); + } + } + else + { + // there is no shortcut to unpack. source and target are on the same EBG Node. + // if the offset of the target is greater than the offset of the source, subtract it + if (target_phantom.GetForwardDistance() > source_phantom.GetForwardDistance()) + { + // --------->t <-- offsets + // ->s <-- subtract source offset from target offset + // ......... <-- want this distance as result + // entry 0---1---2---3--- <-- 3 is exit node + distance = target_phantom.GetForwardDistance() - source_phantom.GetForwardDistance(); + } + else + { + // s<--- <-- offsets + // t<--------- <-- subtract source offset from target offset + // ...... <-- want this distance as result + // entry 0---1---2---3--- <-- 3 is exit node + distance = target_phantom.GetReverseDistance() - source_phantom.GetReverseDistance(); + } + } +} + } // namespace routing_algorithms } // namespace engine } // namespace osrm diff --git a/src/engine/routing_algorithms/routing_base_ch.cpp b/src/engine/routing_algorithms/routing_base_ch.cpp index 695ebe9234a..f9f3485bb98 100644 --- a/src/engine/routing_algorithms/routing_base_ch.cpp +++ b/src/engine/routing_algorithms/routing_base_ch.cpp @@ -199,14 +199,33 @@ double getNetworkDistance(SearchEngineData &engine_working_data, return std::numeric_limits::max(); } - std::vector unpacked_path; - unpackPath(facade, - packed_path.begin(), - packed_path.end(), - {source_phantom, target_phantom}, - unpacked_path); + BOOST_ASSERT(nodes_number > 0); + + EdgeDistance distance = 0; + + std::vector unpacked_nodes; + unpacked_nodes.reserve(packed_path.size()); + if (!packed_path.empty()) + { + unpacked_nodes.push_back(packed_path.front()); + unpackPath(facade, + packed_path.begin(), + packed_path.end(), + [&](std::pair &edge, const auto &) { + BOOST_ASSERT(edge.first == unpacked_nodes.back()); + unpacked_nodes.push_back(edge.second); + }); + + for (auto node_iter = unpacked_nodes.begin(); node_iter != std::prev(unpacked_nodes.end()); + node_iter++) + { + distance += computeEdgeDistance(facade, *node_iter); + } + } + + adjustPathDistanceToPhantomNodes(unpacked_nodes, source_phantom, target_phantom, distance); - return getPathDistance(facade, unpacked_path, source_phantom, target_phantom); + return distance / 10.; } } // namespace ch From b630b4e32a074622e66e3cfbf5cdc2fc7151a04f Mon Sep 17 00:00:00 2001 From: Patrick Niklaus Date: Fri, 27 Apr 2018 05:36:52 +0000 Subject: [PATCH 15/26] Preserve heap state in map matching --- .../routing_algorithms/routing_base.hpp | 141 +++++++++++++----- .../routing_algorithms/routing_base_mld.hpp | 35 +++-- .../routing_algorithms/many_to_many_ch.cpp | 3 +- .../routing_algorithms/map_matching.cpp | 22 ++- .../routing_algorithms/routing_base.cpp | 15 +- .../routing_algorithms/routing_base_ch.cpp | 49 +++--- src/util/coordinate_calculation.cpp | 2 +- 7 files changed, 177 insertions(+), 90 deletions(-) diff --git a/include/engine/routing_algorithms/routing_base.hpp b/include/engine/routing_algorithms/routing_base.hpp index e00f5c4fabb..4d00bf9182e 100644 --- a/include/engine/routing_algorithms/routing_base.hpp +++ b/include/engine/routing_algorithms/routing_base.hpp @@ -44,71 +44,144 @@ bool needsLoopBackwards(const PhantomNode &source_phantom, const PhantomNode &ta bool needsLoopForward(const PhantomNodes &phantoms); bool needsLoopBackwards(const PhantomNodes &phantoms); -template -void insertNodesInHeaps(Heap &forward_heap, Heap &reverse_heap, const PhantomNodes &nodes) +namespace detail { - const auto &source = nodes.source_phantom; - if (source.IsValidForwardSource()) +template +void insertSourceInHeap(typename SearchEngineData::ManyToManyQueryHeap &heap, + const PhantomNode &phantom_node) +{ + if (phantom_node.IsValidForwardTarget()) { - forward_heap.Insert(source.forward_segment_id.id, - -source.GetForwardWeightPlusOffset(), - source.forward_segment_id.id); + heap.Insert(phantom_node.forward_segment_id.id, + -phantom_node.GetForwardWeightPlusOffset(), + {phantom_node.forward_segment_id.id, -phantom_node.GetForwardDuration()}); } - - if (source.IsValidReverseSource()) + if (phantom_node.IsValidReverseTarget()) { - forward_heap.Insert(source.reverse_segment_id.id, - -source.GetReverseWeightPlusOffset(), - source.reverse_segment_id.id); + heap.Insert(phantom_node.reverse_segment_id.id, + -phantom_node.GetReverseWeightPlusOffset(), + {phantom_node.reverse_segment_id.id, -phantom_node.GetReverseDuration()}); } +} - const auto &target = nodes.target_phantom; - if (target.IsValidForwardTarget()) +template +void insertTargetInHeap(typename SearchEngineData::ManyToManyQueryHeap &heap, + const PhantomNode &phantom_node) +{ + if (phantom_node.IsValidForwardTarget()) { - reverse_heap.Insert(target.forward_segment_id.id, - target.GetForwardWeightPlusOffset(), - target.forward_segment_id.id); + heap.Insert(phantom_node.forward_segment_id.id, + phantom_node.GetForwardWeightPlusOffset(), + {phantom_node.forward_segment_id.id, phantom_node.GetForwardDuration()}); } - - if (target.IsValidReverseTarget()) + if (phantom_node.IsValidReverseTarget()) { - reverse_heap.Insert(target.reverse_segment_id.id, - target.GetReverseWeightPlusOffset(), - target.reverse_segment_id.id); + heap.Insert(phantom_node.reverse_segment_id.id, + phantom_node.GetReverseWeightPlusOffset(), + {phantom_node.reverse_segment_id.id, phantom_node.GetReverseDuration()}); } } -template -void insertSourceInHeap(ManyToManyQueryHeap &heap, const PhantomNode &phantom_node) +template +void insertSourceInHeap(typename SearchEngineData::QueryHeap &heap, + const PhantomNode &phantom_node) { if (phantom_node.IsValidForwardSource()) { heap.Insert(phantom_node.forward_segment_id.id, -phantom_node.GetForwardWeightPlusOffset(), - {phantom_node.forward_segment_id.id, -phantom_node.GetForwardDuration()}); + phantom_node.forward_segment_id.id); } if (phantom_node.IsValidReverseSource()) { heap.Insert(phantom_node.reverse_segment_id.id, -phantom_node.GetReverseWeightPlusOffset(), - {phantom_node.reverse_segment_id.id, -phantom_node.GetReverseDuration()}); + phantom_node.reverse_segment_id.id); } } -template -void insertTargetInHeap(ManyToManyQueryHeap &heap, const PhantomNode &phantom_node) +template +void insertTargetInHeap(typename SearchEngineData::QueryHeap &heap, + const PhantomNode &phantom_node) { if (phantom_node.IsValidForwardTarget()) { heap.Insert(phantom_node.forward_segment_id.id, phantom_node.GetForwardWeightPlusOffset(), - {phantom_node.forward_segment_id.id, phantom_node.GetForwardDuration()}); + phantom_node.forward_segment_id.id); } if (phantom_node.IsValidReverseTarget()) { heap.Insert(phantom_node.reverse_segment_id.id, phantom_node.GetReverseWeightPlusOffset(), - {phantom_node.reverse_segment_id.id, phantom_node.GetReverseDuration()}); + phantom_node.reverse_segment_id.id); + } +} +} // namespace detail + +inline void insertTargetInHeap(typename SearchEngineData::ManyToManyQueryHeap &heap, + const PhantomNode &phantom_node) +{ + detail::insertTargetInHeap(heap, phantom_node); +} +inline void insertTargetInHeap(typename SearchEngineData::ManyToManyQueryHeap &heap, + const PhantomNode &phantom_node) +{ + detail::insertTargetInHeap(heap, phantom_node); +} +inline void insertTargetInHeap(typename SearchEngineData::QueryHeap &heap, + const PhantomNode &phantom_node) +{ + detail::insertTargetInHeap(heap, phantom_node); +} +inline void insertTargetInHeap(typename SearchEngineData::QueryHeap &heap, + const PhantomNode &phantom_node) +{ + detail::insertTargetInHeap(heap, phantom_node); +} +inline void insertSourceInHeap(typename SearchEngineData::ManyToManyQueryHeap &heap, + const PhantomNode &phantom_node) +{ + detail::insertSourceInHeap(heap, phantom_node); +} +inline void insertSourceInHeap(typename SearchEngineData::ManyToManyQueryHeap &heap, + const PhantomNode &phantom_node) +{ + detail::insertSourceInHeap(heap, phantom_node); +} +inline void insertSourceInHeap(typename SearchEngineData::QueryHeap &heap, + const PhantomNode &phantom_node) +{ + detail::insertSourceInHeap(heap, phantom_node); +} +inline void insertSourceInHeap(typename SearchEngineData::QueryHeap &heap, + const PhantomNode &phantom_node) +{ + detail::insertSourceInHeap(heap, phantom_node); +} + +template +void insertNodesInHeaps(Heap &forward_heap, Heap &reverse_heap, const PhantomNodes &nodes) +{ + insertSourceInHeap(forward_heap, nodes.source_phantom); + insertTargetInHeap(reverse_heap, nodes.target_phantom); +} + +template +void insertSourceInHeap(typename SearchEngineData::ManyToManyQueryHeap &heap, + const PhantomNode &phantom_node) +{ + if (phantom_node.IsValidForwardSource()) + { + heap.Insert(phantom_node.forward_segment_id.id, + -phantom_node.GetForwardWeightPlusOffset(), + {phantom_node.forward_segment_id.id, -phantom_node.GetForwardDuration()}); + } + if (phantom_node.IsValidReverseSource()) + { + heap.Insert(phantom_node.reverse_segment_id.id, + -phantom_node.GetReverseWeightPlusOffset(), + {phantom_node.reverse_segment_id.id, -phantom_node.GetReverseDuration()}); } } @@ -321,10 +394,10 @@ void annotatePath(const FacadeT &facade, } } -void adjustPathDistanceToPhantomNodes(const std::vector &path, - const PhantomNode &source_phantom, - const PhantomNode &target_phantom, - EdgeDistance &distance); +EdgeDistance adjustPathDistanceToPhantomNodes(const std::vector &path, + const PhantomNode &source_phantom, + const PhantomNode &target_phantom, + const EdgeDistance distance); template InternalRouteResult extractRoute(const DataFacade &facade, diff --git a/include/engine/routing_algorithms/routing_base_mld.hpp b/include/engine/routing_algorithms/routing_base_mld.hpp index d893369f568..a5141a6bcb1 100644 --- a/include/engine/routing_algorithms/routing_base_mld.hpp +++ b/include/engine/routing_algorithms/routing_base_mld.hpp @@ -97,7 +97,6 @@ inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition, const std::vector &phantom_indices) { auto min_level = [&partition, node](const PhantomNode &phantom_node) { - const auto &forward_segment = phantom_node.forward_segment_id; const auto forward_level = forward_segment.enabled ? partition.GetHighestDifferentLevel(node, forward_segment.id) @@ -391,21 +390,27 @@ UnpackedPath search(SearchEngineData &engine_working_data, EdgeWeight weight_upper_bound, Args... args) { - if (forward_heap.Empty() || reverse_heap.Empty()) + if (forward_heap.Empty() && reverse_heap.Empty()) { return std::make_tuple(INVALID_EDGE_WEIGHT, std::vector(), std::vector()); } const auto &partition = facade.GetMultiLevelPartition(); - BOOST_ASSERT(!forward_heap.Empty() && forward_heap.MinKey() < INVALID_EDGE_WEIGHT); - BOOST_ASSERT(!reverse_heap.Empty() && reverse_heap.MinKey() < INVALID_EDGE_WEIGHT); + BOOST_ASSERT(forward_heap.Empty() || forward_heap.MinKey() < INVALID_EDGE_WEIGHT); + BOOST_ASSERT(reverse_heap.Empty() || reverse_heap.MinKey() < INVALID_EDGE_WEIGHT); // run two-Target Dijkstra routing step. NodeID middle = SPECIAL_NODEID; EdgeWeight weight = weight_upper_bound; - EdgeWeight forward_heap_min = forward_heap.MinKey(); - EdgeWeight reverse_heap_min = reverse_heap.MinKey(); + + EdgeWeight forward_heap_min = 0; + if (!forward_heap.Empty()) + forward_heap_min = forward_heap.MinKey(); + EdgeWeight reverse_heap_min = 0; + if (!reverse_heap.Empty()) + reverse_heap_min = reverse_heap.MinKey(); + while (forward_heap.Size() + reverse_heap.Size() > 0 && forward_heap_min + reverse_heap_min < weight) { @@ -657,11 +662,7 @@ double getNetworkDistance(SearchEngineData &engine_working_data, const PhantomNode &target_phantom, EdgeWeight weight_upper_bound = INVALID_EDGE_WEIGHT) { - forward_heap.Clear(); - reverse_heap.Clear(); - const PhantomNodes phantom_nodes{source_phantom, target_phantom}; - insertNodesInHeaps(forward_heap, reverse_heap, phantom_nodes); EdgeWeight weight = INVALID_EDGE_WEIGHT; std::vector unpacked_nodes; @@ -684,16 +685,18 @@ double getNetworkDistance(SearchEngineData &engine_working_data, if (!unpacked_nodes.empty()) { - for (auto node_iter = unpacked_nodes.begin(); node_iter != std::prev(unpacked_nodes.end()); node_iter++) - { - distance += computeEdgeDistance(facade, *node_iter); - } + distance = std::accumulate(unpacked_nodes.begin(), + std::prev(unpacked_nodes.end()), + EdgeDistance{0}, + [&](const EdgeDistance distance, const auto node_id) { + return distance + computeEdgeDistance(facade, node_id); + }); } - adjustPathDistanceToPhantomNodes( + distance = adjustPathDistanceToPhantomNodes( unpacked_nodes, phantom_nodes.source_phantom, phantom_nodes.target_phantom, distance); - return distance / 10.; + return distance; } } // namespace mld diff --git a/src/engine/routing_algorithms/many_to_many_ch.cpp b/src/engine/routing_algorithms/many_to_many_ch.cpp index 00449b9cbb1..496bada8fad 100644 --- a/src/engine/routing_algorithms/many_to_many_ch.cpp +++ b/src/engine/routing_algorithms/many_to_many_ch.cpp @@ -242,7 +242,8 @@ void calculateDistances(typename SearchEngineData::ManyToManyQuer { EdgeDistance annotation = ch::calculateEBGNodeAnnotations(facade, packed_leg.begin(), packed_leg.end()); - adjustPathDistanceToPhantomNodes(packed_leg, source_phantom, target_phantom, annotation); + annotation = adjustPathDistanceToPhantomNodes( + packed_leg, source_phantom, target_phantom, annotation); distances_table[row_index * number_of_targets + column_index] = annotation; } diff --git a/src/engine/routing_algorithms/map_matching.cpp b/src/engine/routing_algorithms/map_matching.cpp index 7d1b75901a5..daefc04c9dc 100644 --- a/src/engine/routing_algorithms/map_matching.cpp +++ b/src/engine/routing_algorithms/map_matching.cpp @@ -227,6 +227,9 @@ SubMatchingList mapMatching(SearchEngineData &engine_working_data, { continue; } + forward_heap.Clear(); + const auto &source_phantom = prev_unbroken_timestamps_list[s].phantom_node; + insertSourceInHeap(forward_heap, source_phantom); for (const auto s_prime : util::irange(0UL, current_viterbi.size())) { @@ -237,14 +240,17 @@ SubMatchingList mapMatching(SearchEngineData &engine_working_data, continue; } - double network_distance = - getNetworkDistance(engine_working_data, - facade, - forward_heap, - reverse_heap, - prev_unbroken_timestamps_list[s].phantom_node, - current_timestamps_list[s_prime].phantom_node, - weight_upper_bound); + reverse_heap.Clear(); + const auto &target_phantom = current_timestamps_list[s_prime].phantom_node; + insertTargetInHeap(reverse_heap, target_phantom); + + double network_distance = getNetworkDistance(engine_working_data, + facade, + forward_heap, + reverse_heap, + source_phantom, + target_phantom, + weight_upper_bound); // get distance diff between loc1/2 and locs/s_prime const auto d_t = std::abs(network_distance - haversine_distance); diff --git a/src/engine/routing_algorithms/routing_base.cpp b/src/engine/routing_algorithms/routing_base.cpp index 236e957fea1..472a8cc9e59 100644 --- a/src/engine/routing_algorithms/routing_base.cpp +++ b/src/engine/routing_algorithms/routing_base.cpp @@ -33,11 +33,12 @@ bool needsLoopBackwards(const PhantomNodes &phantoms) return needsLoopBackwards(phantoms.source_phantom, phantoms.target_phantom); } -void adjustPathDistanceToPhantomNodes(const std::vector &path, - const PhantomNode &source_phantom, - const PhantomNode &target_phantom, - EdgeDistance &distance) +EdgeDistance adjustPathDistanceToPhantomNodes(const std::vector &path, + const PhantomNode &source_phantom, + const PhantomNode &target_phantom, + const EdgeDistance uncorrected_distance) { + EdgeDistance distance = uncorrected_distance; if (!path.empty()) { @@ -97,6 +98,12 @@ void adjustPathDistanceToPhantomNodes(const std::vector &path, distance = target_phantom.GetReverseDistance() - source_phantom.GetReverseDistance(); } } + + BOOST_ASSERT_MSG(distance >= 0 || distance > -1.0f, + "Distance correction generated negative number"); + // guard against underflow errors caused by rounding + distance = std::max(EdgeDistance{0}, distance); + return distance; } } // namespace routing_algorithms diff --git a/src/engine/routing_algorithms/routing_base_ch.cpp b/src/engine/routing_algorithms/routing_base_ch.cpp index f9f3485bb98..d118f86f464 100644 --- a/src/engine/routing_algorithms/routing_base_ch.cpp +++ b/src/engine/routing_algorithms/routing_base_ch.cpp @@ -100,7 +100,7 @@ void search(SearchEngineData & /*engine_working_data*/, const PhantomNodes & /*phantom_nodes*/, const EdgeWeight weight_upper_bound) { - if (forward_heap.Empty() || reverse_heap.Empty()) + if (forward_heap.Empty() && reverse_heap.Empty()) { weight = INVALID_EDGE_WEIGHT; return; @@ -110,10 +110,14 @@ void search(SearchEngineData & /*engine_working_data*/, weight = weight_upper_bound; // get offset to account for offsets on phantom nodes on compressed edges - const auto min_edge_offset = std::min(0, forward_heap.MinKey()); - BOOST_ASSERT(min_edge_offset <= 0); + EdgeWeight min_edge_offset = 0; + if (forward_heap.Size() > 0) + { + min_edge_offset = std::min(min_edge_offset, forward_heap.MinKey()); + BOOST_ASSERT(min_edge_offset <= 0); + } // we only every insert negative offsets for nodes in the forward heap - BOOST_ASSERT(reverse_heap.MinKey() >= 0); + BOOST_ASSERT(reverse_heap.Empty() || reverse_heap.MinKey() >= 0); // run two-Target Dijkstra routing step. while (0 < (forward_heap.Size() + reverse_heap.Size())) @@ -176,11 +180,6 @@ double getNetworkDistance(SearchEngineData &engine_working_data, const PhantomNode &target_phantom, EdgeWeight weight_upper_bound) { - forward_heap.Clear(); - reverse_heap.Clear(); - - insertNodesInHeaps(forward_heap, reverse_heap, {source_phantom, target_phantom}); - EdgeWeight weight = INVALID_EDGE_WEIGHT; std::vector packed_path; search(engine_working_data, @@ -199,8 +198,6 @@ double getNetworkDistance(SearchEngineData &engine_working_data, return std::numeric_limits::max(); } - BOOST_ASSERT(nodes_number > 0); - EdgeDistance distance = 0; std::vector unpacked_nodes; @@ -208,24 +205,24 @@ double getNetworkDistance(SearchEngineData &engine_working_data, if (!packed_path.empty()) { unpacked_nodes.push_back(packed_path.front()); - unpackPath(facade, - packed_path.begin(), - packed_path.end(), - [&](std::pair &edge, const auto &) { - BOOST_ASSERT(edge.first == unpacked_nodes.back()); - unpacked_nodes.push_back(edge.second); - }); - - for (auto node_iter = unpacked_nodes.begin(); node_iter != std::prev(unpacked_nodes.end()); - node_iter++) - { - distance += computeEdgeDistance(facade, *node_iter); - } + unpackPath( + facade, packed_path.begin(), packed_path.end(), [&](const auto &edge, const auto &) { + BOOST_ASSERT(edge.first == unpacked_nodes.back()); + unpacked_nodes.push_back(edge.second); + }); + + distance = std::accumulate(unpacked_nodes.begin(), + std::prev(unpacked_nodes.end()), + EdgeDistance{0}, + [&](const EdgeDistance distance, const auto node_id) { + return distance + computeEdgeDistance(facade, node_id); + }); } - adjustPathDistanceToPhantomNodes(unpacked_nodes, source_phantom, target_phantom, distance); + distance = + adjustPathDistanceToPhantomNodes(unpacked_nodes, source_phantom, target_phantom, distance); - return distance / 10.; + return distance; } } // namespace ch diff --git a/src/util/coordinate_calculation.cpp b/src/util/coordinate_calculation.cpp index 4303375ff12..eb852aa3006 100644 --- a/src/util/coordinate_calculation.cpp +++ b/src/util/coordinate_calculation.cpp @@ -25,7 +25,7 @@ namespace // earth radius varies between 6,356.750-6,378.135 km (3,949.901-3,963.189mi) // The IUGG value for the equatorial radius is 6378.137 km (3963.19 miles) -const constexpr long double EARTH_RADIUS = 6372797.560856; +const constexpr double EARTH_RADIUS = 6372797.560856; class CheapRulerContainer { From c0124f7d77e521f38714f7874d298884bed31481 Mon Sep 17 00:00:00 2001 From: Patrick Niklaus Date: Sun, 22 Jul 2018 15:26:21 +0000 Subject: [PATCH 16/26] Round network distance to deci-meter to retain previous behavior --- src/engine/routing_algorithms/map_matching.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/engine/routing_algorithms/map_matching.cpp b/src/engine/routing_algorithms/map_matching.cpp index daefc04c9dc..72b89d77a21 100644 --- a/src/engine/routing_algorithms/map_matching.cpp +++ b/src/engine/routing_algorithms/map_matching.cpp @@ -252,6 +252,8 @@ SubMatchingList mapMatching(SearchEngineData &engine_working_data, target_phantom, weight_upper_bound); + network_distance = std::round(network_distance*10)/10; + // get distance diff between loc1/2 and locs/s_prime const auto d_t = std::abs(network_distance - haversine_distance); From 8473be69d2ed5805990f9b2855309f27b7f97e24 Mon Sep 17 00:00:00 2001 From: Patrick Niklaus Date: Fri, 20 Jul 2018 15:24:13 +0000 Subject: [PATCH 17/26] Adjust text cases for flightly different matching due to rounding --- features/testbot/matching.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/testbot/matching.feature b/features/testbot/matching.feature index 599afcb1dae..3f33984435c 100644 --- a/features/testbot/matching.feature +++ b/features/testbot/matching.feature @@ -792,4 +792,4 @@ Feature: Basic Map Matching When I match I should get | trace | geometry | a:distance | a:duration | a:weight | duration | | 2345 | 1.00018,1,1.000315,1 | 15.013264 | 1.5 | 1.5 | 1.5 | - | 4321 | 1.00027,1,1.000135,1 | 15.013264 | 1.5 | 1.5 | 1.5 | \ No newline at end of file + | 4321 | 1.00027,1,1.000135,1 | 15.013264 | 1.5 | 1.5 | 1.5 | From 0f78f7b2cc506672d77eb1b8f1d8077c45dd6b55 Mon Sep 17 00:00:00 2001 From: Patrick Niklaus Date: Tue, 24 Jul 2018 12:39:04 +0000 Subject: [PATCH 18/26] Fix bug in computation of distance offset for phantom node --- include/engine/geospatial_query.hpp | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/include/engine/geospatial_query.hpp b/include/engine/geospatial_query.hpp index 4ecfc8118bd..ded53c7cb1b 100644 --- a/include/engine/geospatial_query.hpp +++ b/include/engine/geospatial_query.hpp @@ -449,6 +449,7 @@ template class GeospatialQuery const auto reverse_durations = datafacade.GetUncompressedReverseDurations(geometry_id); const auto forward_geometry = datafacade.GetUncompressedForwardGeometry(geometry_id); + const auto reverse_geometry = datafacade.GetUncompressedReverseGeometry(geometry_id); const auto forward_weight_offset = std::accumulate(forward_weights.begin(), @@ -479,19 +480,19 @@ template class GeospatialQuery datafacade.GetCoordinateOfNode(forward_geometry(data.fwd_segment_position)), point_on_segment); - const auto reverse_weight_offset = - std::accumulate(reverse_weights.begin(), - reverse_weights.end() - data.fwd_segment_position - 1, - EdgeWeight{0}); + const auto rev_segment_position = reverse_weights.size() - data.fwd_segment_position - 1; + + const auto reverse_weight_offset = std::accumulate( + reverse_weights.begin(), reverse_weights.begin() + rev_segment_position, EdgeWeight{0}); const auto reverse_duration_offset = std::accumulate(reverse_durations.begin(), - reverse_durations.end() - data.fwd_segment_position - 1, + reverse_durations.begin() + rev_segment_position, EdgeDuration{0}); EdgeDistance reverse_distance_offset = 0; - for (auto current = forward_geometry.begin(); - current < forward_geometry.end() - data.fwd_segment_position - 2; + for (auto current = reverse_geometry.begin(); + current < reverse_geometry.begin() + rev_segment_position; ++current) { reverse_distance_offset += util::coordinate_calculation::fccApproximateDistance( @@ -499,13 +500,11 @@ template class GeospatialQuery datafacade.GetCoordinateOfNode(*std::next(current))); } - EdgeWeight reverse_weight = - reverse_weights[reverse_weights.size() - data.fwd_segment_position - 1]; - EdgeDuration reverse_duration = - reverse_durations[reverse_durations.size() - data.fwd_segment_position - 1]; + EdgeWeight reverse_weight = reverse_weights[rev_segment_position]; + EdgeDuration reverse_duration = reverse_durations[rev_segment_position]; EdgeDistance reverse_distance = util::coordinate_calculation::fccApproximateDistance( point_on_segment, - datafacade.GetCoordinateOfNode(forward_geometry(data.fwd_segment_position + 1))); + datafacade.GetCoordinateOfNode(reverse_geometry(rev_segment_position))); ratio = std::min(1.0, std::max(0.0, ratio)); if (data.forward_segment_id.id != SPECIAL_SEGMENTID) @@ -693,7 +692,7 @@ template class GeospatialQuery const CoordinateList &coordinates; DataFacadeT &datafacade; }; -} -} +} // namespace engine +} // namespace osrm #endif From 5bd7d04fe3401ab00555b21ed78ce293d172b2ba Mon Sep 17 00:00:00 2001 From: Patrick Niklaus Date: Tue, 24 Jul 2018 12:39:25 +0000 Subject: [PATCH 19/26] Fix formating --- src/engine/routing_algorithms/map_matching.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/routing_algorithms/map_matching.cpp b/src/engine/routing_algorithms/map_matching.cpp index 72b89d77a21..695ec5778c6 100644 --- a/src/engine/routing_algorithms/map_matching.cpp +++ b/src/engine/routing_algorithms/map_matching.cpp @@ -252,7 +252,7 @@ SubMatchingList mapMatching(SearchEngineData &engine_working_data, target_phantom, weight_upper_bound); - network_distance = std::round(network_distance*10)/10; + network_distance = std::round(network_distance * 10) / 10; // get distance diff between loc1/2 and locs/s_prime const auto d_t = std::abs(network_distance - haversine_distance); From 9b779c704f2cfe4e25c3609da7e30e0bc751a633 Mon Sep 17 00:00:00 2001 From: Patrick Niklaus Date: Tue, 24 Jul 2018 12:53:29 +0000 Subject: [PATCH 20/26] Update changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 64f392aa5dd..9f208680c31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,10 @@ # UNRELEASED - Changes from 5.18.0: + - Optimizations: + - CHANGED: Map matching is now almost twice as fast. [#5060](https://github.com/Project-OSRM/osrm-backend/pull/5060) - Bugfixes: - FIXED: collapsing of ExitRoundabout instructions [#5114](https://github.com/Project-OSRM/osrm-backend/issues/5114) + - FIXED: negative distances in table plugin annotation [#5106](https://github.com/Project-OSRM/osrm-backend/issues/5106) # 5.18.0 - Changes from 5.17.0: From 69d7825542bd8e55d4cd11d68c7f21fad72ec1f6 Mon Sep 17 00:00:00 2001 From: Daniel Patterson Date: Tue, 28 Aug 2018 18:12:19 -0700 Subject: [PATCH 21/26] Increase allowed shared memory regions to 512 from ~120 --- CHANGELOG.md | 2 ++ include/storage/shared_datatype.hpp | 19 +++++++++---------- include/storage/shared_memory.hpp | 19 ++++++++++--------- include/storage/shared_monitor.hpp | 10 ++++++---- src/storage/storage.cpp | 2 +- src/tools/store.cpp | 3 ++- 6 files changed, 30 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f208680c31..54a57a6c2d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ - Bugfixes: - FIXED: collapsing of ExitRoundabout instructions [#5114](https://github.com/Project-OSRM/osrm-backend/issues/5114) - FIXED: negative distances in table plugin annotation [#5106](https://github.com/Project-OSRM/osrm-backend/issues/5106) + - Misc: + - CHANGED: Support up to 512 named shared memory regions [#5185](https://github.com/Project-OSRM/osrm-backend/pull/5185) # 5.18.0 - Changes from 5.17.0: diff --git a/include/storage/shared_datatype.hpp b/include/storage/shared_datatype.hpp index 720a37d464c..926ca1deddf 100644 --- a/include/storage/shared_datatype.hpp +++ b/include/storage/shared_datatype.hpp @@ -26,7 +26,7 @@ namespace serialization inline void read(io::BufferReader &reader, DataLayout &layout); inline void write(io::BufferWriter &writer, const DataLayout &layout); -} +} // namespace serialization namespace detail { @@ -52,7 +52,7 @@ inline std::string trimName(const std::string &name_prefix, const std::string &n return name; } } -} +} // namespace detail class DataLayout { @@ -165,7 +165,7 @@ struct SharedRegion static constexpr const int MAX_NAME_LENGTH = 254; SharedRegion() : name{0}, timestamp{0} {} - SharedRegion(const std::string &name_, std::uint64_t timestamp, std::uint8_t shm_key) + SharedRegion(const std::string &name_, std::uint64_t timestamp, std::uint16_t shm_key) : name{0}, timestamp{timestamp}, shm_key{shm_key} { std::copy_n(name_.begin(), std::min(MAX_NAME_LENGTH, name_.size()), name); @@ -175,14 +175,14 @@ struct SharedRegion char name[MAX_NAME_LENGTH + 1]; std::uint64_t timestamp; - std::uint8_t shm_key; + std::uint16_t shm_key; }; // Keeps a list of all shared regions in a fixed-sized struct // for fast access and deserialization. struct SharedRegionRegister { - using RegionID = std::uint8_t; + using RegionID = std::uint16_t; static constexpr const RegionID INVALID_REGION_ID = std::numeric_limits::max(); using ShmKey = decltype(SharedRegion::shm_key); @@ -250,12 +250,11 @@ struct SharedRegionRegister void ReleaseKey(ShmKey key) { shm_key_in_use[key] = false; } - static constexpr const std::uint8_t MAX_SHARED_REGIONS = - std::numeric_limits::max() - 1; + static constexpr const std::size_t MAX_SHARED_REGIONS = 512; static_assert(MAX_SHARED_REGIONS < std::numeric_limits::max(), "Number of shared memory regions needs to be less than the region id size."); - static constexpr const std::uint8_t MAX_SHM_KEYS = std::numeric_limits::max() - 1; + static constexpr const std::size_t MAX_SHM_KEYS = MAX_SHARED_REGIONS * 2; static constexpr const char *name = "osrm-region"; @@ -263,7 +262,7 @@ struct SharedRegionRegister std::array regions; std::array shm_key_in_use; }; -} -} +} // namespace storage +} // namespace osrm #endif /* SHARED_DATA_TYPE_HPP */ diff --git a/include/storage/shared_memory.hpp b/include/storage/shared_memory.hpp index 6fdedfcef9e..3b558238d35 100644 --- a/include/storage/shared_memory.hpp +++ b/include/storage/shared_memory.hpp @@ -34,10 +34,10 @@ namespace storage struct OSRMLockFile { - boost::filesystem::path operator()() + template boost::filesystem::path operator()(const IdentifierT &id) { boost::filesystem::path temp_dir = boost::filesystem::temp_directory_path(); - boost::filesystem::path lock_file = temp_dir / "osrm.lock"; + boost::filesystem::path lock_file = temp_dir / ("osrm-" + std::to_string(id) + ".lock"); return lock_file; } }; @@ -93,7 +93,7 @@ class SharedMemory try { OSRMLockFile lock_file; - boost::interprocess::xsi_key key(lock_file().string().c_str(), id); + boost::interprocess::xsi_key key(lock_file(id).string().c_str(), id); result = RegionExists(key); } catch (...) @@ -106,7 +106,7 @@ class SharedMemory template static bool Remove(const IdentifierT id) { OSRMLockFile lock_file; - boost::interprocess::xsi_key key(lock_file().string().c_str(), id); + boost::interprocess::xsi_key key(lock_file(id).string().c_str(), id); return Remove(key); } @@ -287,10 +287,11 @@ class SharedMemory template std::unique_ptr makeSharedMemory(const IdentifierT &id, const uint64_t size = 0) { + static_assert(sizeof(id) == sizeof(std::uint16_t), "Key type is not 16 bits"); try { LockFileT lock_file; - if (!boost::filesystem::exists(lock_file())) + if (!boost::filesystem::exists(lock_file(id))) { if (0 == size) { @@ -298,10 +299,10 @@ std::unique_ptr makeSharedMemory(const IdentifierT &id, const uint } else { - boost::filesystem::ofstream ofs(lock_file()); + boost::filesystem::ofstream ofs(lock_file(id)); } } - return std::make_unique(lock_file(), id, size); + return std::make_unique(lock_file(id), id, size); } catch (const boost::interprocess::interprocess_exception &e) { @@ -310,7 +311,7 @@ std::unique_ptr makeSharedMemory(const IdentifierT &id, const uint throw util::exception(e.what() + SOURCE_REF); } } -} -} +} // namespace storage +} // namespace osrm #endif // SHARED_MEMORY_HPP diff --git a/include/storage/shared_monitor.hpp b/include/storage/shared_monitor.hpp index 46048e48745..2084112d452 100644 --- a/include/storage/shared_monitor.hpp +++ b/include/storage/shared_monitor.hpp @@ -33,7 +33,7 @@ template class InvertedLock InvertedLock(Lock &lock) : lock(lock) { lock.unlock(); } ~InvertedLock() { lock.lock(); } }; -} +} // namespace // The shared monitor implementation based on a semaphore and mutex template struct SharedMonitor @@ -146,7 +146,9 @@ template struct SharedMonitor // like two-turnstile reusable barrier or boost/interprocess/sync/spin/condition.hpp // fail if a waiter is killed. - static constexpr int buffer_size = 256; + // Buffer size needs to be large enough to hold all the semaphores for every + // listener you want to support. + static constexpr int buffer_size = 4096 * 4; struct InternalData { @@ -232,8 +234,8 @@ template struct SharedMonitor bi::shared_memory_object shmem; bi::mapped_region region; }; -} -} +} // namespace storage +} // namespace osrm #undef USE_BOOST_INTERPROCESS_CONDITION diff --git a/src/storage/storage.cpp b/src/storage/storage.cpp index bcdf0325291..213217425f8 100644 --- a/src/storage/storage.cpp +++ b/src/storage/storage.cpp @@ -66,7 +66,7 @@ struct RegionHandle { std::unique_ptr memory; char *data_ptr; - std::uint8_t shm_key; + std::uint16_t shm_key; }; auto setupRegion(SharedRegionRegister &shared_register, const DataLayout &layout) diff --git a/src/tools/store.cpp b/src/tools/store.cpp index cf9d965264d..bd21c9b4b1d 100644 --- a/src/tools/store.cpp +++ b/src/tools/store.cpp @@ -82,7 +82,8 @@ void springClean() } else { - for (auto key : util::irange(0, storage::SharedRegionRegister::MAX_SHM_KEYS)) + for (auto key : util::irange( + 0, storage::SharedRegionRegister::MAX_SHM_KEYS)) { deleteRegion(key); } From 85515f063a7d72658b62148cd84043aa073eefa2 Mon Sep 17 00:00:00 2001 From: Daniel Patterson Date: Sat, 1 Sep 2018 20:47:27 -0700 Subject: [PATCH 22/26] Render floating point numbers to string using Grisu2 algorithmt instead of stdlib to speed up JSON generation. --- CHANGELOG.md | 1 + include/util/ieee754.hpp | 517 +++++++++++++++++++++++++++++++++ include/util/json_renderer.hpp | 33 ++- 3 files changed, 549 insertions(+), 2 deletions(-) create mode 100644 include/util/ieee754.hpp diff --git a/CHANGELOG.md b/CHANGELOG.md index 54a57a6c2d9..6cd59ea493f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ - Changes from 5.18.0: - Optimizations: - CHANGED: Map matching is now almost twice as fast. [#5060](https://github.com/Project-OSRM/osrm-backend/pull/5060) + - CHANGED: Use Grisu2 for serializing floating point numbers. [#5188](https://github.com/Project-OSRM/osrm-backend/pull/5188) - Bugfixes: - FIXED: collapsing of ExitRoundabout instructions [#5114](https://github.com/Project-OSRM/osrm-backend/issues/5114) - FIXED: negative distances in table plugin annotation [#5106](https://github.com/Project-OSRM/osrm-backend/issues/5106) diff --git a/include/util/ieee754.hpp b/include/util/ieee754.hpp new file mode 100644 index 00000000000..6a05c26f47d --- /dev/null +++ b/include/util/ieee754.hpp @@ -0,0 +1,517 @@ +#ifndef IEEE754_HPP +#define IEEE754_HPP +/** +Copyright (C) 2014 Milo Yip + +Imported from: +https://github.com/miloyip/dtoa-benchmark/blob/c4020c62754950d38a1aaaed2975b05b441d1e7d/src/milo/dtoa_milo.h + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +**/ + +#include +#include + +#if defined(_MSC_VER) +#include "msinttypes/stdint.h" +#include +#else +#include +#endif + +#define UINT64_C2(h, l) ((static_cast(h) << 32) | static_cast(l)) + +namespace osrm +{ +namespace util +{ +namespace ieee754 +{ + +struct DiyFp +{ + DiyFp() {} + + DiyFp(uint64_t f, int e) : f(f), e(e) {} + + DiyFp(double d) + { + union { + double d; + uint64_t u64; + } u = {d}; + + int biased_e = (u.u64 & kDpExponentMask) >> kDpSignificandSize; + uint64_t significand = (u.u64 & kDpSignificandMask); + if (biased_e != 0) + { + f = significand + kDpHiddenBit; + e = biased_e - kDpExponentBias; + } + else + { + f = significand; + e = kDpMinExponent + 1; + } + } + + DiyFp operator-(const DiyFp &rhs) const + { + assert(e == rhs.e); + assert(f >= rhs.f); + return DiyFp(f - rhs.f, e); + } + + DiyFp operator*(const DiyFp &rhs) const + { +#if defined(_MSC_VER) && defined(_M_AMD64) + uint64_t h; + uint64_t l = _umul128(f, rhs.f, &h); + if (l & (uint64_t(1) << 63)) // rounding + h++; + return DiyFp(h, e + rhs.e + 64); +#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__) + unsigned __int128 p = + static_cast(f) * static_cast(rhs.f); + uint64_t h = p >> 64; + uint64_t l = static_cast(p); + if (l & (uint64_t(1) << 63)) // rounding + h++; + return DiyFp(h, e + rhs.e + 64); +#else + const uint64_t M32 = 0xFFFFFFFF; + const uint64_t a = f >> 32; + const uint64_t b = f & M32; + const uint64_t c = rhs.f >> 32; + const uint64_t d = rhs.f & M32; + const uint64_t ac = a * c; + const uint64_t bc = b * c; + const uint64_t ad = a * d; + const uint64_t bd = b * d; + uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32); + tmp += 1U << 31; /// mult_round + return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64); +#endif + } + + DiyFp Normalize() const + { +#if defined(_MSC_VER) && defined(_M_AMD64) + unsigned long index; + _BitScanReverse64(&index, f); + return DiyFp(f << (63 - index), e - (63 - index)); +#elif defined(__GNUC__) + int s = __builtin_clzll(f); + return DiyFp(f << s, e - s); +#else + DiyFp res = *this; + while (!(res.f & kDpHiddenBit)) + { + res.f <<= 1; + res.e--; + } + res.f <<= (kDiySignificandSize - kDpSignificandSize - 1); + res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 1); + return res; +#endif + } + + DiyFp NormalizeBoundary() const + { +#if defined(_MSC_VER) && defined(_M_AMD64) + unsigned long index; + _BitScanReverse64(&index, f); + return DiyFp(f << (63 - index), e - (63 - index)); +#else + DiyFp res = *this; + while (!(res.f & (kDpHiddenBit << 1))) + { + res.f <<= 1; + res.e--; + } + res.f <<= (kDiySignificandSize - kDpSignificandSize - 2); + res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2); + return res; +#endif + } + + void NormalizedBoundaries(DiyFp *minus, DiyFp *plus) const + { + DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary(); + DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1); + mi.f <<= mi.e - pl.e; + mi.e = pl.e; + *plus = pl; + *minus = mi; + } + + static const int kDiySignificandSize = 64; + static const int kDpSignificandSize = 52; + static const int kDpExponentBias = 0x3FF + kDpSignificandSize; + static const int kDpMinExponent = -kDpExponentBias; + static const uint64_t kDpExponentMask = UINT64_C2(0x7FF00000, 0x00000000); + static const uint64_t kDpSignificandMask = UINT64_C2(0x000FFFFF, 0xFFFFFFFF); + static const uint64_t kDpHiddenBit = UINT64_C2(0x00100000, 0x00000000); + + uint64_t f; + int e; +}; + +inline DiyFp GetCachedPower(int e, int *K) +{ + // 10^-348, 10^-340, ..., 10^340 + static const uint64_t kCachedPowers_F[] = { + UINT64_C2(0xfa8fd5a0, 0x081c0288), UINT64_C2(0xbaaee17f, 0xa23ebf76), + UINT64_C2(0x8b16fb20, 0x3055ac76), UINT64_C2(0xcf42894a, 0x5dce35ea), + UINT64_C2(0x9a6bb0aa, 0x55653b2d), UINT64_C2(0xe61acf03, 0x3d1a45df), + UINT64_C2(0xab70fe17, 0xc79ac6ca), UINT64_C2(0xff77b1fc, 0xbebcdc4f), + UINT64_C2(0xbe5691ef, 0x416bd60c), UINT64_C2(0x8dd01fad, 0x907ffc3c), + UINT64_C2(0xd3515c28, 0x31559a83), UINT64_C2(0x9d71ac8f, 0xada6c9b5), + UINT64_C2(0xea9c2277, 0x23ee8bcb), UINT64_C2(0xaecc4991, 0x4078536d), + UINT64_C2(0x823c1279, 0x5db6ce57), UINT64_C2(0xc2109436, 0x4dfb5637), + UINT64_C2(0x9096ea6f, 0x3848984f), UINT64_C2(0xd77485cb, 0x25823ac7), + UINT64_C2(0xa086cfcd, 0x97bf97f4), UINT64_C2(0xef340a98, 0x172aace5), + UINT64_C2(0xb23867fb, 0x2a35b28e), UINT64_C2(0x84c8d4df, 0xd2c63f3b), + UINT64_C2(0xc5dd4427, 0x1ad3cdba), UINT64_C2(0x936b9fce, 0xbb25c996), + UINT64_C2(0xdbac6c24, 0x7d62a584), UINT64_C2(0xa3ab6658, 0x0d5fdaf6), + UINT64_C2(0xf3e2f893, 0xdec3f126), UINT64_C2(0xb5b5ada8, 0xaaff80b8), + UINT64_C2(0x87625f05, 0x6c7c4a8b), UINT64_C2(0xc9bcff60, 0x34c13053), + UINT64_C2(0x964e858c, 0x91ba2655), UINT64_C2(0xdff97724, 0x70297ebd), + UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), UINT64_C2(0xf8a95fcf, 0x88747d94), + UINT64_C2(0xb9447093, 0x8fa89bcf), UINT64_C2(0x8a08f0f8, 0xbf0f156b), + UINT64_C2(0xcdb02555, 0x653131b6), UINT64_C2(0x993fe2c6, 0xd07b7fac), + UINT64_C2(0xe45c10c4, 0x2a2b3b06), UINT64_C2(0xaa242499, 0x697392d3), + UINT64_C2(0xfd87b5f2, 0x8300ca0e), UINT64_C2(0xbce50864, 0x92111aeb), + UINT64_C2(0x8cbccc09, 0x6f5088cc), UINT64_C2(0xd1b71758, 0xe219652c), + UINT64_C2(0x9c400000, 0x00000000), UINT64_C2(0xe8d4a510, 0x00000000), + UINT64_C2(0xad78ebc5, 0xac620000), UINT64_C2(0x813f3978, 0xf8940984), + UINT64_C2(0xc097ce7b, 0xc90715b3), UINT64_C2(0x8f7e32ce, 0x7bea5c70), + UINT64_C2(0xd5d238a4, 0xabe98068), UINT64_C2(0x9f4f2726, 0x179a2245), + UINT64_C2(0xed63a231, 0xd4c4fb27), UINT64_C2(0xb0de6538, 0x8cc8ada8), + UINT64_C2(0x83c7088e, 0x1aab65db), UINT64_C2(0xc45d1df9, 0x42711d9a), + UINT64_C2(0x924d692c, 0xa61be758), UINT64_C2(0xda01ee64, 0x1a708dea), + UINT64_C2(0xa26da399, 0x9aef774a), UINT64_C2(0xf209787b, 0xb47d6b85), + UINT64_C2(0xb454e4a1, 0x79dd1877), UINT64_C2(0x865b8692, 0x5b9bc5c2), + UINT64_C2(0xc83553c5, 0xc8965d3d), UINT64_C2(0x952ab45c, 0xfa97a0b3), + UINT64_C2(0xde469fbd, 0x99a05fe3), UINT64_C2(0xa59bc234, 0xdb398c25), + UINT64_C2(0xf6c69a72, 0xa3989f5c), UINT64_C2(0xb7dcbf53, 0x54e9bece), + UINT64_C2(0x88fcf317, 0xf22241e2), UINT64_C2(0xcc20ce9b, 0xd35c78a5), + UINT64_C2(0x98165af3, 0x7b2153df), UINT64_C2(0xe2a0b5dc, 0x971f303a), + UINT64_C2(0xa8d9d153, 0x5ce3b396), UINT64_C2(0xfb9b7cd9, 0xa4a7443c), + UINT64_C2(0xbb764c4c, 0xa7a44410), UINT64_C2(0x8bab8eef, 0xb6409c1a), + UINT64_C2(0xd01fef10, 0xa657842c), UINT64_C2(0x9b10a4e5, 0xe9913129), + UINT64_C2(0xe7109bfb, 0xa19c0c9d), UINT64_C2(0xac2820d9, 0x623bf429), + UINT64_C2(0x80444b5e, 0x7aa7cf85), UINT64_C2(0xbf21e440, 0x03acdd2d), + UINT64_C2(0x8e679c2f, 0x5e44ff8f), UINT64_C2(0xd433179d, 0x9c8cb841), + UINT64_C2(0x9e19db92, 0xb4e31ba9), UINT64_C2(0xeb96bf6e, 0xbadf77d9), + UINT64_C2(0xaf87023b, 0x9bf0ee6b)}; + static const int16_t kCachedPowers_E[] = { + -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, -954, -927, -901, + -874, -847, -821, -794, -768, -741, -715, -688, -661, -635, -608, -582, -555, + -529, -502, -475, -449, -422, -396, -369, -343, -316, -289, -263, -236, -210, + -183, -157, -130, -103, -77, -50, -24, 3, 30, 56, 83, 109, 136, + 162, 189, 216, 242, 269, 295, 322, 348, 375, 402, 428, 455, 481, + 508, 534, 561, 588, 614, 641, 667, 694, 720, 747, 774, 800, 827, + 853, 880, 907, 933, 960, 986, 1013, 1039, 1066}; + + // int k = static_cast(ceil((-61 - e) * 0.30102999566398114)) + 374; + double dk = + (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive + int k = static_cast(dk); + if (k != dk) + k++; + + unsigned index = static_cast((k >> 3) + 1); + *K = -(-348 + static_cast(index << 3)); // decimal exponent no need lookup table + + assert(index < sizeof(kCachedPowers_F) / sizeof(kCachedPowers_F[0])); + return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]); +} + +inline void +GrisuRound(char *buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) +{ + while (rest < wp_w && delta - rest >= ten_kappa && (rest + ten_kappa < wp_w || /// closer + wp_w - rest > rest + ten_kappa - wp_w)) + { + buffer[len - 1]--; + rest += ten_kappa; + } +} + +inline unsigned CountDecimalDigit32(uint32_t n) +{ + // Simple pure C++ implementation was faster than __builtin_clz version in this situation. + if (n < 10) + return 1; + if (n < 100) + return 2; + if (n < 1000) + return 3; + if (n < 10000) + return 4; + if (n < 100000) + return 5; + if (n < 1000000) + return 6; + if (n < 10000000) + return 7; + if (n < 100000000) + return 8; + if (n < 1000000000) + return 9; + return 10; +} + +inline void +DigitGen(const DiyFp &W, const DiyFp &Mp, uint64_t delta, char *buffer, int *len, int *K) +{ + static const uint32_t kPow10[] = { + 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000}; + const DiyFp one(uint64_t(1) << -Mp.e, Mp.e); + const DiyFp wp_w = Mp - W; + uint32_t p1 = static_cast(Mp.f >> -one.e); + uint64_t p2 = Mp.f & (one.f - 1); + int kappa = static_cast(CountDecimalDigit32(p1)); + *len = 0; + + while (kappa > 0) + { + uint32_t d; + switch (kappa) + { + case 10: + d = p1 / 1000000000; + p1 %= 1000000000; + break; + case 9: + d = p1 / 100000000; + p1 %= 100000000; + break; + case 8: + d = p1 / 10000000; + p1 %= 10000000; + break; + case 7: + d = p1 / 1000000; + p1 %= 1000000; + break; + case 6: + d = p1 / 100000; + p1 %= 100000; + break; + case 5: + d = p1 / 10000; + p1 %= 10000; + break; + case 4: + d = p1 / 1000; + p1 %= 1000; + break; + case 3: + d = p1 / 100; + p1 %= 100; + break; + case 2: + d = p1 / 10; + p1 %= 10; + break; + case 1: + d = p1; + p1 = 0; + break; + default: +#if defined(_MSC_VER) + __assume(0); +#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) + __builtin_unreachable(); +#else + d = 0; +#endif + } + if (d || *len) + buffer[(*len)++] = '0' + static_cast(d); + kappa--; + uint64_t tmp = (static_cast(p1) << -one.e) + p2; + if (tmp <= delta) + { + *K += kappa; + GrisuRound( + buffer, *len, delta, tmp, static_cast(kPow10[kappa]) << -one.e, wp_w.f); + return; + } + } + + // kappa = 0 + for (;;) + { + p2 *= 10; + delta *= 10; + char d = static_cast(p2 >> -one.e); + if (d || *len) + buffer[(*len)++] = '0' + d; + p2 &= one.f - 1; + kappa--; + if (p2 < delta) + { + *K += kappa; + GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * kPow10[-kappa]); + return; + } + } +} + +inline void Grisu2(double value, char *buffer, int *length, int *K) +{ + const DiyFp v(value); + DiyFp w_m, w_p; + v.NormalizedBoundaries(&w_m, &w_p); + + const DiyFp c_mk = GetCachedPower(w_p.e, K); + const DiyFp W = v.Normalize() * c_mk; + DiyFp Wp = w_p * c_mk; + DiyFp Wm = w_m * c_mk; + Wm.f++; + Wp.f--; + DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K); +} + +inline const char *GetDigitsLut() +{ + static const char cDigitsLut[200] = { + '0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6', '0', '7', '0', + '8', '0', '9', '1', '0', '1', '1', '1', '2', '1', '3', '1', '4', '1', '5', '1', '6', + '1', '7', '1', '8', '1', '9', '2', '0', '2', '1', '2', '2', '2', '3', '2', '4', '2', + '5', '2', '6', '2', '7', '2', '8', '2', '9', '3', '0', '3', '1', '3', '2', '3', '3', + '3', '4', '3', '5', '3', '6', '3', '7', '3', '8', '3', '9', '4', '0', '4', '1', '4', + '2', '4', '3', '4', '4', '4', '5', '4', '6', '4', '7', '4', '8', '4', '9', '5', '0', + '5', '1', '5', '2', '5', '3', '5', '4', '5', '5', '5', '6', '5', '7', '5', '8', '5', + '9', '6', '0', '6', '1', '6', '2', '6', '3', '6', '4', '6', '5', '6', '6', '6', '7', + '6', '8', '6', '9', '7', '0', '7', '1', '7', '2', '7', '3', '7', '4', '7', '5', '7', + '6', '7', '7', '7', '8', '7', '9', '8', '0', '8', '1', '8', '2', '8', '3', '8', '4', + '8', '5', '8', '6', '8', '7', '8', '8', '8', '9', '9', '0', '9', '1', '9', '2', '9', + '3', '9', '4', '9', '5', '9', '6', '9', '7', '9', '8', '9', '9'}; + return cDigitsLut; +} + +inline void WriteExponent(int K, char *buffer) +{ + if (K < 0) + { + *buffer++ = '-'; + K = -K; + } + + if (K >= 100) + { + *buffer++ = '0' + static_cast(K / 100); + K %= 100; + const char *d = GetDigitsLut() + K * 2; + *buffer++ = d[0]; + *buffer++ = d[1]; + } + else if (K >= 10) + { + const char *d = GetDigitsLut() + K * 2; + *buffer++ = d[0]; + *buffer++ = d[1]; + } + else + *buffer++ = '0' + static_cast(K); + + *buffer = '\0'; +} + +inline void Prettify(char *buffer, int length, int k) +{ + const int kk = length + k; // 10^(kk-1) <= v < 10^kk + + if (length <= kk && kk <= 21) + { + // 1234e7 -> 12340000000 + for (int i = length; i < kk; i++) + buffer[i] = '0'; + buffer[kk] = '.'; + buffer[kk + 1] = '0'; + buffer[kk + 2] = '\0'; + } + else if (0 < kk && kk <= 21) + { + // 1234e-2 -> 12.34 + memmove(&buffer[kk + 1], &buffer[kk], length - kk); + buffer[kk] = '.'; + buffer[length + 1] = '\0'; + } + else if (-6 < kk && kk <= 0) + { + // 1234e-6 -> 0.001234 + const int offset = 2 - kk; + memmove(&buffer[offset], &buffer[0], length); + buffer[0] = '0'; + buffer[1] = '.'; + for (int i = 2; i < offset; i++) + buffer[i] = '0'; + buffer[length + offset] = '\0'; + } + else if (length == 1) + { + // 1e30 + buffer[1] = 'e'; + WriteExponent(kk - 1, &buffer[2]); + } + else + { + // 1234e30 -> 1.234e33 + memmove(&buffer[2], &buffer[1], length - 1); + buffer[1] = '.'; + buffer[length + 1] = 'e'; + WriteExponent(kk - 1, &buffer[0 + length + 2]); + } +} + +inline void dtoa_milo(double value, char *buffer) +{ + // Not handling NaN and inf + assert(!isnan(value)); + assert(!isinf(value)); + + if (value == 0) + { + buffer[0] = '0'; + buffer[1] = '.'; + buffer[2] = '0'; + buffer[3] = '\0'; + } + else + { + if (value < 0) + { + *buffer++ = '-'; + value = -value; + } + int length, K; + Grisu2(value, buffer, &length, &K); + Prettify(buffer, length, K); + } +} +} // namespace ieee754 +} // namespace util +} // namespace osrm + +#endif // IEEE754_HPP \ No newline at end of file diff --git a/include/util/json_renderer.hpp b/include/util/json_renderer.hpp index f83524b28c4..5d6a24228ed 100644 --- a/include/util/json_renderer.hpp +++ b/include/util/json_renderer.hpp @@ -5,6 +5,7 @@ #define JSON_RENDERER_HPP #include "util/cast.hpp" +#include "util/ieee754.hpp" #include "util/string_util.hpp" #include "osrm/json_container.hpp" @@ -21,6 +22,11 @@ namespace util namespace json { +namespace +{ +constexpr int MAX_FLOAT_STRING_LENGTH = 256; +} + struct Renderer { explicit Renderer(std::ostream &_out) : out(_out) {} @@ -34,8 +40,31 @@ struct Renderer void operator()(const Number &number) const { - out.precision(10); - out << number.value; + char buffer[MAX_FLOAT_STRING_LENGTH] = {'\0'}; + ieee754::dtoa_milo(number.value, buffer); + + // Trucate to 10 decimal places + int pos = 0; + int decimalpos = 0; + while (decimalpos == 0 && pos < MAX_FLOAT_STRING_LENGTH && buffer[pos] != 0) + { + if (buffer[pos] == '.') + { + decimalpos = pos; + break; + } + ++pos; + } + while (pos < MAX_FLOAT_STRING_LENGTH && buffer[pos] != 0) + { + if (pos - decimalpos == 10) + { + buffer[pos] = '\0'; + break; + } + ++pos; + } + out << buffer; } void operator()(const Object &object) const From 0971f06193db834011740d7d756184a7838c5736 Mon Sep 17 00:00:00 2001 From: Daniel Patterson Date: Sat, 1 Sep 2018 22:22:37 -0700 Subject: [PATCH 23/26] Add option to node bindings to return result as a pre-generated JSON string (this avoids a lot of overhead, and moves JSON string rendering out of the main event loop). --- CHANGELOG.md | 1 + docs/nodejs/api.md | 23 ++++++ include/nodejs/node_osrm_support.hpp | 73 +++++++++++++++++-- src/nodejs/node_osrm.cpp | 103 ++++++++++++++++++++++++--- test/nodejs/match.js | 32 +++++++++ test/nodejs/nearest.js | 21 +++++- test/nodejs/route.js | 18 ++++- test/nodejs/table.js | 19 ++++- test/nodejs/trip.js | 17 ++++- 9 files changed, 287 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6cd59ea493f..3dc24cbaa54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ - Optimizations: - CHANGED: Map matching is now almost twice as fast. [#5060](https://github.com/Project-OSRM/osrm-backend/pull/5060) - CHANGED: Use Grisu2 for serializing floating point numbers. [#5188](https://github.com/Project-OSRM/osrm-backend/pull/5188) + - ADDED: Node bindings can return pre-rendered JSON buffer. [#5189](https://github.com/Project-OSRM/osrm-backend/pull/5189) - Bugfixes: - FIXED: collapsing of ExitRoundabout instructions [#5114](https://github.com/Project-OSRM/osrm-backend/issues/5114) - FIXED: negative distances in table plugin annotation [#5106](https://github.com/Project-OSRM/osrm-backend/issues/5106) diff --git a/docs/nodejs/api.md b/docs/nodejs/api.md index 01ef653cb43..e729962f013 100644 --- a/docs/nodejs/api.md +++ b/docs/nodejs/api.md @@ -297,6 +297,29 @@ Returns **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refer 2) `waypoint_index`: index of the point in the trip. **`trips`**: an array of [`Route`](#route) objects that assemble the trace. +## Plugin behaviour + +All plugins support a second additional object that is available to configure some NodeJS specific behaviours. + +- `plugin_config` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** Object literal containing parameters for the trip query. + - `plugin_config.format` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** The format of the result object to various API calls. Valid options are `object` (default), which returns a standard Javascript object, as described above, and `json_buffer`, which will return a NodeJS **[Buffer](https://nodejs.org/api/buffer.html)** object, containing a JSON string. The latter has the advantage that it can be immediately serialized to disk/sent over the network, and the generation of the string is performed outside the main NodeJS event loop. This option is ignored by the `tile` plugin. + +**Examples** + +```javascript +var osrm = new OSRM('network.osrm'); +var options = { + coordinates: [ + [13.36761474609375, 52.51663871100423], + [13.374481201171875, 52.506191342034576] + ] +}; +osrm.route(options, { format: "json_buffer" }, function(err, response) { + if (err) throw err; + console.log(response.toString("utf-8")); +}); +``` + ## Responses Responses diff --git a/include/nodejs/node_osrm_support.hpp b/include/nodejs/node_osrm_support.hpp index 6ffea408b66..4a93eb7a74c 100644 --- a/include/nodejs/node_osrm_support.hpp +++ b/include/nodejs/node_osrm_support.hpp @@ -2,6 +2,7 @@ #define OSRM_BINDINGS_NODE_SUPPORT_HPP #include "nodejs/json_v8_renderer.hpp" +#include "util/json_renderer.hpp" #include "osrm/approach.hpp" #include "osrm/bearing.hpp" @@ -24,6 +25,7 @@ #include #include #include +#include #include #include @@ -42,6 +44,13 @@ using match_parameters_ptr = std::unique_ptr; using nearest_parameters_ptr = std::unique_ptr; using table_parameters_ptr = std::unique_ptr; +struct PluginParameters +{ + bool renderJSONToBuffer = false; +}; + +using ObjectOrString = typename mapbox::util::variant; + template inline v8::Local render(const ResultT &result); template <> v8::Local inline render(const std::string &result) @@ -49,11 +58,21 @@ template <> v8::Local inline render(const std::string &result) return Nan::CopyBuffer(result.data(), result.size()).ToLocalChecked(); } -template <> v8::Local inline render(const osrm::json::Object &result) +template <> v8::Local inline render(const ObjectOrString &result) { - v8::Local value; - renderToV8(value, result); - return value; + if (result.is()) + { + // Convert osrm::json object tree into matching v8 object tree + v8::Local value; + renderToV8(value, result.get()); + return value; + } + else + { + // Return the string object as a node Buffer + return Nan::CopyBuffer(result.get().data(), result.get().size()) + .ToLocalChecked(); + } } inline void ParseResult(const osrm::Status &result_status, osrm::json::Object &result) @@ -814,6 +833,50 @@ inline bool parseCommonParameters(const v8::Local &obj, ParamType &p return true; } +inline PluginParameters +argumentsToPluginParameters(const Nan::FunctionCallbackInfo &args) +{ + if (args.Length() < 3 || !args[1]->IsObject()) + { + return {}; + } + v8::Local obj = Nan::To(args[1]).ToLocalChecked(); + if (obj->Has(Nan::New("format").ToLocalChecked())) + { + + v8::Local format = obj->Get(Nan::New("format").ToLocalChecked()); + if (format.IsEmpty()) + { + return {}; + } + + if (!format->IsString()) + { + Nan::ThrowError("format must be a string: \"object\" or \"json_buffer\""); + return {}; + } + + const Nan::Utf8String format_utf8str(format); + std::string format_str{*format_utf8str, *format_utf8str + format_utf8str.length()}; + + if (format_str == "object") + { + return {false}; + } + else if (format_str == "json_buffer") + { + return {true}; + } + else + { + Nan::ThrowError("format must be a string: \"object\" or \"json_buffer\""); + return {}; + } + } + + return {}; +} + inline route_parameters_ptr argumentsToRouteParameter(const Nan::FunctionCallbackInfo &args, bool requires_multiple_coordinates) @@ -1357,6 +1420,6 @@ argumentsToMatchParameter(const Nan::FunctionCallbackInfo &args, return params; } -} // ns node_osrm +} // namespace node_osrm #endif diff --git a/src/nodejs/node_osrm.cpp b/src/nodejs/node_osrm.cpp index aa7e03851f6..14d970c775a 100644 --- a/src/nodejs/node_osrm.cpp +++ b/src/nodejs/node_osrm.cpp @@ -9,12 +9,15 @@ #include "osrm/trip_parameters.hpp" #include +#include #include #include #include "nodejs/node_osrm.hpp" #include "nodejs/node_osrm_support.hpp" +#include "util/json_renderer.hpp" + namespace node_osrm { @@ -122,6 +125,8 @@ inline void async(const Nan::FunctionCallbackInfo &info, if (!params) return; + auto pluginParams = argumentsToPluginParameters(info); + BOOST_ASSERT(params->IsValid()); if (!info[info.Length() - 1]->IsFunction()) @@ -137,9 +142,89 @@ inline void async(const Nan::FunctionCallbackInfo &info, Worker(std::shared_ptr osrm_, ParamPtr params_, ServiceMemFn service, - Nan::Callback *callback) + Nan::Callback *callback, + PluginParameters pluginParams_) : Base(callback), osrm{std::move(osrm_)}, service{std::move(service)}, - params{std::move(params_)} + params{std::move(params_)}, pluginParams{std::move(pluginParams_)} + { + } + + void Execute() override try + { + osrm::json::Object r; + const auto status = ((*osrm).*(service))(*params, r); + ParseResult(status, r); + if (pluginParams.renderJSONToBuffer) + { + std::ostringstream buf; + osrm::util::json::render(buf, r); + result = buf.str(); + } + else + { + result = r; + } + } + catch (const std::exception &e) + { + SetErrorMessage(e.what()); + } + + void HandleOKCallback() override + { + Nan::HandleScope scope; + + const constexpr auto argc = 2u; + v8::Local argv[argc] = {Nan::Null(), render(result)}; + + callback->Call(argc, argv); + } + + // Keeps the OSRM object alive even after shutdown until we're done with callback + std::shared_ptr osrm; + ServiceMemFn service; + const ParamPtr params; + const PluginParameters pluginParams; + + ObjectOrString result; + }; + + auto *callback = new Nan::Callback{info[info.Length() - 1].As()}; + Nan::AsyncQueueWorker( + new Worker{self->this_, std::move(params), service, callback, std::move(pluginParams)}); +} + +template +inline void asyncForTiles(const Nan::FunctionCallbackInfo &info, + ParameterParser argsToParams, + ServiceMemFn service, + bool requires_multiple_coordinates) +{ + auto params = argsToParams(info, requires_multiple_coordinates); + if (!params) + return; + + auto pluginParams = argumentsToPluginParameters(info); + + BOOST_ASSERT(params->IsValid()); + + if (!info[info.Length() - 1]->IsFunction()) + return Nan::ThrowTypeError("last argument must be a callback function"); + + auto *const self = Nan::ObjectWrap::Unwrap(info.Holder()); + using ParamPtr = decltype(params); + + struct Worker final : Nan::AsyncWorker + { + using Base = Nan::AsyncWorker; + + Worker(std::shared_ptr osrm_, + ParamPtr params_, + ServiceMemFn service, + Nan::Callback *callback, + PluginParameters pluginParams_) + : Base(callback), osrm{std::move(osrm_)}, service{std::move(service)}, + params{std::move(params_)}, pluginParams{std::move(pluginParams_)} { } @@ -167,18 +252,14 @@ inline void async(const Nan::FunctionCallbackInfo &info, std::shared_ptr osrm; ServiceMemFn service; const ParamPtr params; + const PluginParameters pluginParams; - // All services return json::Object .. except for Tile! - using ObjectOrString = - typename std::conditional::value, - std::string, - osrm::json::Object>::type; - - ObjectOrString result; + std::string result; }; auto *callback = new Nan::Callback{info[info.Length() - 1].As()}; - Nan::AsyncQueueWorker(new Worker{self->this_, std::move(params), service, callback}); + Nan::AsyncQueueWorker( + new Worker{self->this_, std::move(params), service, callback, std::move(pluginParams)}); } // clang-format off @@ -341,7 +422,7 @@ NAN_METHOD(Engine::table) // // clang-format on NAN_METHOD(Engine::tile) { - async(info, &argumentsToTileParameters, &osrm::OSRM::Tile, {/*unused*/}); + asyncForTiles(info, &argumentsToTileParameters, &osrm::OSRM::Tile, {/*unused*/}); } // clang-format off diff --git a/test/nodejs/match.js b/test/nodejs/match.js index 10b5a72eb9d..da4d7853b0e 100644 --- a/test/nodejs/match.js +++ b/test/nodejs/match.js @@ -25,6 +25,28 @@ test('match: match in Monaco', function(assert) { }); }); +test('match: match in Monaco returning a buffer', function(assert) { + assert.plan(6); + var osrm = new OSRM(data_path); + var options = { + coordinates: three_test_coordinates, + timestamps: [1424684612, 1424684616, 1424684620] + }; + osrm.match(options, { format: 'json_buffer' }, function(err, response) { + assert.ifError(err); + assert.ok(response instanceof Buffer); + response = JSON.parse(response); + assert.equal(response.matchings.length, 1); + assert.ok(response.matchings.every(function(m) { + return !!m.distance && !!m.duration && Array.isArray(m.legs) && !!m.geometry && m.confidence > 0; + })) + assert.equal(response.tracepoints.length, 3); + assert.ok(response.tracepoints.every(function(t) { + return !!t.hint && !isNaN(t.matchings_index) && !isNaN(t.waypoint_index) && !!t.name; + })); + }); +}); + test('match: match in Monaco without timestamps', function(assert) { assert.plan(3); var osrm = new OSRM(data_path); @@ -225,6 +247,16 @@ test('match: throws on invalid tidy param', function(assert) { /tidy must be of type Boolean/); }); +test('match: throws on invalid config param', function(assert) { + assert.plan(1); + var osrm = new OSRM({path: mld_data_path, algorithm: 'MLD'}); + var options = { + coordinates: three_test_coordinates, + }; + assert.throws(function() { osrm.match(options, { format: 'invalid' }, function(err, response) {}) }, + /format must be a string:/); +}); + test('match: match in Monaco without motorways', function(assert) { assert.plan(3); var osrm = new OSRM({path: mld_data_path, algorithm: 'MLD'}); diff --git a/test/nodejs/nearest.js b/test/nodejs/nearest.js index 4a038dbe535..1fce37af054 100644 --- a/test/nodejs/nearest.js +++ b/test/nodejs/nearest.js @@ -19,6 +19,21 @@ test('nearest', function(assert) { }); }); +test('nearest', function(assert) { + assert.plan(5); + var osrm = new OSRM(data_path); + osrm.nearest({ + coordinates: [three_test_coordinates[0]] + }, { format: 'json_buffer' }, function(err, result) { + assert.ifError(err); + assert.ok(result instanceof Buffer); + result = JSON.parse(result); + assert.equal(result.waypoints.length, 1); + assert.equal(result.waypoints[0].location.length, 2); + assert.ok(result.waypoints[0].hasOwnProperty('name')); + }); +}); + test('nearest: can ask for multiple nearest pts', function(assert) { assert.plan(2); var osrm = new OSRM(data_path); @@ -32,7 +47,7 @@ test('nearest: can ask for multiple nearest pts', function(assert) { }); test('nearest: throws on invalid args', function(assert) { - assert.plan(6); + assert.plan(7); var osrm = new OSRM(data_path); var options = {}; assert.throws(function() { osrm.nearest(options); }, @@ -52,6 +67,10 @@ test('nearest: throws on invalid args', function(assert) { options.number = 0; assert.throws(function() { osrm.nearest(options, function(err, res) {}); }, /Number must be an integer greater than or equal to 1/); + + options.number = 1; + assert.throws(function() { osrm.nearest(options, { format: 'invalid' }, function(err, res) {}); }, + /format must be a string:/); }); test('nearest: nearest in Monaco without motorways', function(assert) { diff --git a/test/nodejs/route.js b/test/nodejs/route.js index ae28f3762d5..011a098a30c 100644 --- a/test/nodejs/route.js +++ b/test/nodejs/route.js @@ -43,8 +43,22 @@ test('route: routes Monaco on CoreCH', function(assert) { }); }); +test('route: routes Monaco and returns a JSON buffer', function(assert) { + assert.plan(6); + var osrm = new OSRM({path: monaco_corech_path, algorithm: 'CoreCH'}); + osrm.route({coordinates: [[13.43864,52.51993],[13.415852,52.513191]]}, { format: 'json_buffer'}, function(err, result) { + assert.ifError(err); + assert.ok(result instanceof Buffer); + const route = JSON.parse(result); + assert.ok(route.waypoints); + assert.ok(route.routes); + assert.ok(route.routes.length); + assert.ok(route.routes[0].geometry); + }); +}); + test('route: throws with too few or invalid args', function(assert) { - assert.plan(3); + assert.plan(4); var osrm = new OSRM(monaco_path); assert.throws(function() { osrm.route({coordinates: two_test_coordinates}) }, /Two arguments required/); @@ -52,6 +66,8 @@ test('route: throws with too few or invalid args', function(assert) { /First arg must be an object/); assert.throws(function() { osrm.route({coordinates: two_test_coordinates}, true)}, /last argument must be a callback function/); + assert.throws(function() { osrm.route({coordinates: two_test_coordinates}, { format: 'invalid' }, function(err, route) {})}, + /format must be a string:/); }); test('route: provides no alternatives by default, but when requested it may (not guaranteed)', function(assert) { diff --git a/test/nodejs/table.js b/test/nodejs/table.js index 220added1b0..e763eea866e 100644 --- a/test/nodejs/table.js +++ b/test/nodejs/table.js @@ -48,6 +48,20 @@ test('table: test annotations paramater combination', function(assert) { }); }); +test('table: returns buffer', function(assert) { + assert.plan(3); + var osrm = new OSRM(data_path); + var options = { + coordinates: [three_test_coordinates[0], three_test_coordinates[1]], + }; + osrm.table(options, { format: 'json_buffer' }, function(err, table) { + assert.ifError(err); + assert.ok(table instanceof Buffer); + table = JSON.parse(table); + assert.ok(table['durations'], 'distances table result should exist'); + }); +}); + var tables = ['distances', 'durations']; tables.forEach(function(annotation) { @@ -116,7 +130,7 @@ tables.forEach(function(annotation) { }); test('table: ' + annotation + ' throws on invalid arguments', function(assert) { - assert.plan(14); + assert.plan(15); var osrm = new OSRM(data_path); var options = {annotations: [annotation.slice(0,-1)]}; assert.throws(function() { osrm.table(options); }, @@ -135,6 +149,9 @@ tables.forEach(function(annotation) { /Coordinates must be an array of \(lon\/lat\) pairs/); options.coordinates = two_test_coordinates; + assert.throws(function() { osrm.table(options, { format: 'invalid' }, function(err, response) {}) }, + /format must be a string:/); + options.sources = true; assert.throws(function() { osrm.table(options, function(err, response) {}) }, /Sources must be an array of indices \(or undefined\)/); diff --git a/test/nodejs/trip.js b/test/nodejs/trip.js index ff2294712db..f26d97b83ca 100644 --- a/test/nodejs/trip.js +++ b/test/nodejs/trip.js @@ -17,6 +17,19 @@ test('trip: trip in Monaco', function(assert) { }); }); +test('trip: trip in Monaco as a buffer', function(assert) { + assert.plan(3); + var osrm = new OSRM(data_path); + osrm.trip({coordinates: two_test_coordinates}, { format: 'json_buffer' }, function(err, trip) { + assert.ifError(err); + assert.ok(trip instanceof Buffer); + trip = JSON.parse(trip); + for (t = 0; t < trip.trips.length; t++) { + assert.ok(trip.trips[t].geometry); + } + }); +}); + test('trip: trip with many locations in Monaco', function(assert) { assert.plan(2); @@ -33,12 +46,14 @@ test('trip: trip with many locations in Monaco', function(assert) { }); test('trip: throws with too few or invalid args', function(assert) { - assert.plan(2); + assert.plan(3); var osrm = new OSRM(data_path); assert.throws(function() { osrm.trip({coordinates: two_test_coordinates}) }, /Two arguments required/); assert.throws(function() { osrm.trip(null, function(err, trip) {}) }, /First arg must be an object/); + assert.throws(function() { osrm.trip({coordinates: two_test_coordinates}, { format: 'invalid' }, function(err, trip) {}) }, + /format must be a string:/); }); test('trip: throws with bad params', function(assert) { From 5476f6ab274503a56b135591c77184aa31e24682 Mon Sep 17 00:00:00 2001 From: Jie Date: Thu, 6 Sep 2018 07:23:48 +0800 Subject: [PATCH 24/26] Fix GDB not work for osrm-routed on Linux (#5157) As I mentioned in the issue #5156, I met below issue on my Win10+WSL(Ubuntu) env: The remote debugger (VSCode on Win10, gdb on Ubuntu 18.04 LTS) works well from the beginning of the main() function. But when I step over the code pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask); (src/tools/routed.cpp(289)), below breakpoints can not work and displayed unverified breakpoint. Then I found that gdb breakpoint need at least SIGTRAP, SIGSTOP to work (Please refer to [how debugger works](http://www.alexonlinux.com/how-debugger-works) for more details), but all signals are blocked in the source code until server initialized done. In my understanding, block all signals DO NOT make sense for this osrm-routed process. Only several signals (SIGINT, SIGQUIT, SIGTERM) are expected to wait. So I made the change and it works well for me then. --- CHANGELOG.md | 1 + src/tools/routed.cpp | 22 +++++++++------------- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3dc24cbaa54..5562c92bf89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - ADDED: Node bindings can return pre-rendered JSON buffer. [#5189](https://github.com/Project-OSRM/osrm-backend/pull/5189) - Bugfixes: - FIXED: collapsing of ExitRoundabout instructions [#5114](https://github.com/Project-OSRM/osrm-backend/issues/5114) + - FIXED: fix osrm-routed gdb not work issue [#5156](https://github.com/Project-OSRM/osrm-backend/issues/5156) - FIXED: negative distances in table plugin annotation [#5106](https://github.com/Project-OSRM/osrm-backend/issues/5106) - Misc: - CHANGED: Support up to 512 named shared memory regions [#5185](https://github.com/Project-OSRM/osrm-backend/pull/5185) diff --git a/src/tools/routed.cpp b/src/tools/routed.cpp index 66236d527da..25a62b03aae 100644 --- a/src/tools/routed.cpp +++ b/src/tools/routed.cpp @@ -70,8 +70,8 @@ std::istream &operator>>(std::istream &in, EngineConfig::Algorithm &algorithm) throw util::RuntimeError(token, ErrorCode::UnknownAlgorithm, SOURCE_REF); return in; } -} -} +} // namespace engine +} // namespace osrm // generate boost::program_options object for the routing part inline unsigned generateServerProgramOptions(const int argc, @@ -273,10 +273,12 @@ int main(int argc, const char *argv[]) try #ifndef _WIN32 int sig = 0; - sigset_t new_mask; - sigset_t old_mask; - sigfillset(&new_mask); - pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask); + sigset_t wait_mask; + sigemptyset(&wait_mask); + sigaddset(&wait_mask, SIGINT); + sigaddset(&wait_mask, SIGQUIT); + sigaddset(&wait_mask, SIGTERM); + pthread_sigmask(SIG_BLOCK, &wait_mask, nullptr); // only block necessary signals #endif auto service_handler = std::make_unique(config); @@ -298,19 +300,13 @@ int main(int argc, const char *argv[]) try std::thread server_thread(std::move(server_task)); #ifndef _WIN32 - sigset_t wait_mask; - pthread_sigmask(SIG_SETMASK, &old_mask, nullptr); - sigemptyset(&wait_mask); - sigaddset(&wait_mask, SIGINT); - sigaddset(&wait_mask, SIGQUIT); - sigaddset(&wait_mask, SIGTERM); - pthread_sigmask(SIG_BLOCK, &wait_mask, nullptr); util::Log() << "running and waiting for requests"; if (std::getenv("SIGNAL_PARENT_WHEN_READY")) { kill(getppid(), SIGUSR1); } sigwait(&wait_mask, &sig); + util::Log() << "received signal " << sig; #else // Set console control handler to allow server to be stopped. console_ctrl_function = std::bind(&server::Server::Stop, routing_server); From 5597415f28c592a588a2430237b6dfcab95ce0b9 Mon Sep 17 00:00:00 2001 From: Kajari Ghosh Date: Thu, 6 Sep 2018 12:05:28 -0400 Subject: [PATCH 25/26] Revert "Improve speed of Map Matching" (#5196) * Revert "Update changelog" This reverts commit 9b779c704f2cfe4e25c3609da7e30e0bc751a633. * Revert "Fix formating" This reverts commit 5bd7d04fe3401ab00555b21ed78ce293d172b2ba. * Revert "Fix bug in computation of distance offset for phantom node" This reverts commit 0f78f7b2cc506672d77eb1b8f1d8077c45dd6b55. * Revert "Adjust text cases for flightly different matching due to rounding" This reverts commit 8473be69d2ed5805990f9b2855309f27b7f97e24. * Revert "Round network distance to deci-meter to retain previous behavior" This reverts commit c0124f7d77e521f38714f7874d298884bed31481. * Revert "Preserve heap state in map matching" This reverts commit b630b4e32a074622e66e3cfbf5cdc2fc7151a04f. * Revert "Use distance functions from many to many" This reverts commit 89fabc1b9c61545300223b364aa788ab61055721. * Revert "Use FCC algorithm for map matching distance calculation" This reverts commit a649a8a5cfb0b00d02f2bf50bf6c1db387cb9f2e. --- CHANGELOG.md | 2 - features/testbot/matching.feature | 2 +- include/engine/geospatial_query.hpp | 27 +-- .../routing_algorithms/routing_base.hpp | 189 ++++++++---------- .../routing_algorithms/routing_base_mld.hpp | 40 ++-- include/util/coordinate_calculation.hpp | 3 + .../routing_algorithms/many_to_many_ch.cpp | 68 ++++++- .../routing_algorithms/map_matching.cpp | 24 +-- .../routing_algorithms/routing_base.cpp | 73 ------- .../routing_algorithms/routing_base_ch.cpp | 48 ++--- src/util/coordinate_calculation.cpp | 9 +- 11 files changed, 205 insertions(+), 280 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5562c92bf89..2c979444dc7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,8 +6,6 @@ - ADDED: Node bindings can return pre-rendered JSON buffer. [#5189](https://github.com/Project-OSRM/osrm-backend/pull/5189) - Bugfixes: - FIXED: collapsing of ExitRoundabout instructions [#5114](https://github.com/Project-OSRM/osrm-backend/issues/5114) - - FIXED: fix osrm-routed gdb not work issue [#5156](https://github.com/Project-OSRM/osrm-backend/issues/5156) - - FIXED: negative distances in table plugin annotation [#5106](https://github.com/Project-OSRM/osrm-backend/issues/5106) - Misc: - CHANGED: Support up to 512 named shared memory regions [#5185](https://github.com/Project-OSRM/osrm-backend/pull/5185) diff --git a/features/testbot/matching.feature b/features/testbot/matching.feature index 3f33984435c..599afcb1dae 100644 --- a/features/testbot/matching.feature +++ b/features/testbot/matching.feature @@ -792,4 +792,4 @@ Feature: Basic Map Matching When I match I should get | trace | geometry | a:distance | a:duration | a:weight | duration | | 2345 | 1.00018,1,1.000315,1 | 15.013264 | 1.5 | 1.5 | 1.5 | - | 4321 | 1.00027,1,1.000135,1 | 15.013264 | 1.5 | 1.5 | 1.5 | + | 4321 | 1.00027,1,1.000135,1 | 15.013264 | 1.5 | 1.5 | 1.5 | \ No newline at end of file diff --git a/include/engine/geospatial_query.hpp b/include/engine/geospatial_query.hpp index ded53c7cb1b..4ecfc8118bd 100644 --- a/include/engine/geospatial_query.hpp +++ b/include/engine/geospatial_query.hpp @@ -449,7 +449,6 @@ template class GeospatialQuery const auto reverse_durations = datafacade.GetUncompressedReverseDurations(geometry_id); const auto forward_geometry = datafacade.GetUncompressedForwardGeometry(geometry_id); - const auto reverse_geometry = datafacade.GetUncompressedReverseGeometry(geometry_id); const auto forward_weight_offset = std::accumulate(forward_weights.begin(), @@ -480,19 +479,19 @@ template class GeospatialQuery datafacade.GetCoordinateOfNode(forward_geometry(data.fwd_segment_position)), point_on_segment); - const auto rev_segment_position = reverse_weights.size() - data.fwd_segment_position - 1; - - const auto reverse_weight_offset = std::accumulate( - reverse_weights.begin(), reverse_weights.begin() + rev_segment_position, EdgeWeight{0}); + const auto reverse_weight_offset = + std::accumulate(reverse_weights.begin(), + reverse_weights.end() - data.fwd_segment_position - 1, + EdgeWeight{0}); const auto reverse_duration_offset = std::accumulate(reverse_durations.begin(), - reverse_durations.begin() + rev_segment_position, + reverse_durations.end() - data.fwd_segment_position - 1, EdgeDuration{0}); EdgeDistance reverse_distance_offset = 0; - for (auto current = reverse_geometry.begin(); - current < reverse_geometry.begin() + rev_segment_position; + for (auto current = forward_geometry.begin(); + current < forward_geometry.end() - data.fwd_segment_position - 2; ++current) { reverse_distance_offset += util::coordinate_calculation::fccApproximateDistance( @@ -500,11 +499,13 @@ template class GeospatialQuery datafacade.GetCoordinateOfNode(*std::next(current))); } - EdgeWeight reverse_weight = reverse_weights[rev_segment_position]; - EdgeDuration reverse_duration = reverse_durations[rev_segment_position]; + EdgeWeight reverse_weight = + reverse_weights[reverse_weights.size() - data.fwd_segment_position - 1]; + EdgeDuration reverse_duration = + reverse_durations[reverse_durations.size() - data.fwd_segment_position - 1]; EdgeDistance reverse_distance = util::coordinate_calculation::fccApproximateDistance( point_on_segment, - datafacade.GetCoordinateOfNode(reverse_geometry(rev_segment_position))); + datafacade.GetCoordinateOfNode(forward_geometry(data.fwd_segment_position + 1))); ratio = std::min(1.0, std::max(0.0, ratio)); if (data.forward_segment_id.id != SPECIAL_SEGMENTID) @@ -692,7 +693,7 @@ template class GeospatialQuery const CoordinateList &coordinates; DataFacadeT &datafacade; }; -} // namespace engine -} // namespace osrm +} +} #endif diff --git a/include/engine/routing_algorithms/routing_base.hpp b/include/engine/routing_algorithms/routing_base.hpp index 4d00bf9182e..0c0808a3f49 100644 --- a/include/engine/routing_algorithms/routing_base.hpp +++ b/include/engine/routing_algorithms/routing_base.hpp @@ -44,144 +44,71 @@ bool needsLoopBackwards(const PhantomNode &source_phantom, const PhantomNode &ta bool needsLoopForward(const PhantomNodes &phantoms); bool needsLoopBackwards(const PhantomNodes &phantoms); -namespace detail -{ -template -void insertSourceInHeap(typename SearchEngineData::ManyToManyQueryHeap &heap, - const PhantomNode &phantom_node) +template +void insertNodesInHeaps(Heap &forward_heap, Heap &reverse_heap, const PhantomNodes &nodes) { - if (phantom_node.IsValidForwardTarget()) + const auto &source = nodes.source_phantom; + if (source.IsValidForwardSource()) { - heap.Insert(phantom_node.forward_segment_id.id, - -phantom_node.GetForwardWeightPlusOffset(), - {phantom_node.forward_segment_id.id, -phantom_node.GetForwardDuration()}); + forward_heap.Insert(source.forward_segment_id.id, + -source.GetForwardWeightPlusOffset(), + source.forward_segment_id.id); } - if (phantom_node.IsValidReverseTarget()) + + if (source.IsValidReverseSource()) { - heap.Insert(phantom_node.reverse_segment_id.id, - -phantom_node.GetReverseWeightPlusOffset(), - {phantom_node.reverse_segment_id.id, -phantom_node.GetReverseDuration()}); + forward_heap.Insert(source.reverse_segment_id.id, + -source.GetReverseWeightPlusOffset(), + source.reverse_segment_id.id); } -} -template -void insertTargetInHeap(typename SearchEngineData::ManyToManyQueryHeap &heap, - const PhantomNode &phantom_node) -{ - if (phantom_node.IsValidForwardTarget()) + const auto &target = nodes.target_phantom; + if (target.IsValidForwardTarget()) { - heap.Insert(phantom_node.forward_segment_id.id, - phantom_node.GetForwardWeightPlusOffset(), - {phantom_node.forward_segment_id.id, phantom_node.GetForwardDuration()}); + reverse_heap.Insert(target.forward_segment_id.id, + target.GetForwardWeightPlusOffset(), + target.forward_segment_id.id); } - if (phantom_node.IsValidReverseTarget()) + + if (target.IsValidReverseTarget()) { - heap.Insert(phantom_node.reverse_segment_id.id, - phantom_node.GetReverseWeightPlusOffset(), - {phantom_node.reverse_segment_id.id, phantom_node.GetReverseDuration()}); + reverse_heap.Insert(target.reverse_segment_id.id, + target.GetReverseWeightPlusOffset(), + target.reverse_segment_id.id); } } -template -void insertSourceInHeap(typename SearchEngineData::QueryHeap &heap, - const PhantomNode &phantom_node) +template +void insertSourceInHeap(ManyToManyQueryHeap &heap, const PhantomNode &phantom_node) { if (phantom_node.IsValidForwardSource()) { heap.Insert(phantom_node.forward_segment_id.id, -phantom_node.GetForwardWeightPlusOffset(), - phantom_node.forward_segment_id.id); + {phantom_node.forward_segment_id.id, -phantom_node.GetForwardDuration()}); } if (phantom_node.IsValidReverseSource()) { heap.Insert(phantom_node.reverse_segment_id.id, -phantom_node.GetReverseWeightPlusOffset(), - phantom_node.reverse_segment_id.id); + {phantom_node.reverse_segment_id.id, -phantom_node.GetReverseDuration()}); } } -template -void insertTargetInHeap(typename SearchEngineData::QueryHeap &heap, - const PhantomNode &phantom_node) +template +void insertTargetInHeap(ManyToManyQueryHeap &heap, const PhantomNode &phantom_node) { if (phantom_node.IsValidForwardTarget()) { heap.Insert(phantom_node.forward_segment_id.id, phantom_node.GetForwardWeightPlusOffset(), - phantom_node.forward_segment_id.id); + {phantom_node.forward_segment_id.id, phantom_node.GetForwardDuration()}); } if (phantom_node.IsValidReverseTarget()) { heap.Insert(phantom_node.reverse_segment_id.id, phantom_node.GetReverseWeightPlusOffset(), - phantom_node.reverse_segment_id.id); - } -} -} // namespace detail - -inline void insertTargetInHeap(typename SearchEngineData::ManyToManyQueryHeap &heap, - const PhantomNode &phantom_node) -{ - detail::insertTargetInHeap(heap, phantom_node); -} -inline void insertTargetInHeap(typename SearchEngineData::ManyToManyQueryHeap &heap, - const PhantomNode &phantom_node) -{ - detail::insertTargetInHeap(heap, phantom_node); -} -inline void insertTargetInHeap(typename SearchEngineData::QueryHeap &heap, - const PhantomNode &phantom_node) -{ - detail::insertTargetInHeap(heap, phantom_node); -} -inline void insertTargetInHeap(typename SearchEngineData::QueryHeap &heap, - const PhantomNode &phantom_node) -{ - detail::insertTargetInHeap(heap, phantom_node); -} -inline void insertSourceInHeap(typename SearchEngineData::ManyToManyQueryHeap &heap, - const PhantomNode &phantom_node) -{ - detail::insertSourceInHeap(heap, phantom_node); -} -inline void insertSourceInHeap(typename SearchEngineData::ManyToManyQueryHeap &heap, - const PhantomNode &phantom_node) -{ - detail::insertSourceInHeap(heap, phantom_node); -} -inline void insertSourceInHeap(typename SearchEngineData::QueryHeap &heap, - const PhantomNode &phantom_node) -{ - detail::insertSourceInHeap(heap, phantom_node); -} -inline void insertSourceInHeap(typename SearchEngineData::QueryHeap &heap, - const PhantomNode &phantom_node) -{ - detail::insertSourceInHeap(heap, phantom_node); -} - -template -void insertNodesInHeaps(Heap &forward_heap, Heap &reverse_heap, const PhantomNodes &nodes) -{ - insertSourceInHeap(forward_heap, nodes.source_phantom); - insertTargetInHeap(reverse_heap, nodes.target_phantom); -} - -template -void insertSourceInHeap(typename SearchEngineData::ManyToManyQueryHeap &heap, - const PhantomNode &phantom_node) -{ - if (phantom_node.IsValidForwardSource()) - { - heap.Insert(phantom_node.forward_segment_id.id, - -phantom_node.GetForwardWeightPlusOffset(), - {phantom_node.forward_segment_id.id, -phantom_node.GetForwardDuration()}); - } - if (phantom_node.IsValidReverseSource()) - { - heap.Insert(phantom_node.reverse_segment_id.id, - -phantom_node.GetReverseWeightPlusOffset(), - {phantom_node.reverse_segment_id.id, -phantom_node.GetReverseDuration()}); + {phantom_node.reverse_segment_id.id, phantom_node.GetReverseDuration()}); } } @@ -394,10 +321,58 @@ void annotatePath(const FacadeT &facade, } } -EdgeDistance adjustPathDistanceToPhantomNodes(const std::vector &path, - const PhantomNode &source_phantom, - const PhantomNode &target_phantom, - const EdgeDistance distance); +template +double getPathDistance(const DataFacade &facade, + const std::vector unpacked_path, + const PhantomNode &source_phantom, + const PhantomNode &target_phantom) +{ + using util::coordinate_calculation::detail::DEGREE_TO_RAD; + using util::coordinate_calculation::detail::EARTH_RADIUS; + + double distance = 0; + double prev_lat = + static_cast(util::toFloating(source_phantom.location.lat)) * DEGREE_TO_RAD; + double prev_lon = + static_cast(util::toFloating(source_phantom.location.lon)) * DEGREE_TO_RAD; + double prev_cos = std::cos(prev_lat); + for (const auto &p : unpacked_path) + { + const auto current_coordinate = facade.GetCoordinateOfNode(p.turn_via_node); + + const double current_lat = + static_cast(util::toFloating(current_coordinate.lat)) * DEGREE_TO_RAD; + const double current_lon = + static_cast(util::toFloating(current_coordinate.lon)) * DEGREE_TO_RAD; + const double current_cos = std::cos(current_lat); + + const double sin_dlon = std::sin((prev_lon - current_lon) / 2.0); + const double sin_dlat = std::sin((prev_lat - current_lat) / 2.0); + + const double aharv = sin_dlat * sin_dlat + prev_cos * current_cos * sin_dlon * sin_dlon; + const double charv = 2. * std::atan2(std::sqrt(aharv), std::sqrt(1.0 - aharv)); + distance += EARTH_RADIUS * charv; + + prev_lat = current_lat; + prev_lon = current_lon; + prev_cos = current_cos; + } + + const double current_lat = + static_cast(util::toFloating(target_phantom.location.lat)) * DEGREE_TO_RAD; + const double current_lon = + static_cast(util::toFloating(target_phantom.location.lon)) * DEGREE_TO_RAD; + const double current_cos = std::cos(current_lat); + + const double sin_dlon = std::sin((prev_lon - current_lon) / 2.0); + const double sin_dlat = std::sin((prev_lat - current_lat) / 2.0); + + const double aharv = sin_dlat * sin_dlat + prev_cos * current_cos * sin_dlon * sin_dlon; + const double charv = 2. * std::atan2(std::sqrt(aharv), std::sqrt(1.0 - aharv)); + distance += EARTH_RADIUS * charv; + + return distance; +} template InternalRouteResult extractRoute(const DataFacade &facade, diff --git a/include/engine/routing_algorithms/routing_base_mld.hpp b/include/engine/routing_algorithms/routing_base_mld.hpp index a5141a6bcb1..ce9b23d70a0 100644 --- a/include/engine/routing_algorithms/routing_base_mld.hpp +++ b/include/engine/routing_algorithms/routing_base_mld.hpp @@ -97,6 +97,7 @@ inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition, const std::vector &phantom_indices) { auto min_level = [&partition, node](const PhantomNode &phantom_node) { + const auto &forward_segment = phantom_node.forward_segment_id; const auto forward_level = forward_segment.enabled ? partition.GetHighestDifferentLevel(node, forward_segment.id) @@ -119,7 +120,7 @@ inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition, } return result; } -} // namespace +} // Heaps only record for each node its predecessor ("parent") on the shortest path. // For re-constructing the actual path we need to trace back all parent "pointers". @@ -390,27 +391,21 @@ UnpackedPath search(SearchEngineData &engine_working_data, EdgeWeight weight_upper_bound, Args... args) { - if (forward_heap.Empty() && reverse_heap.Empty()) + if (forward_heap.Empty() || reverse_heap.Empty()) { return std::make_tuple(INVALID_EDGE_WEIGHT, std::vector(), std::vector()); } const auto &partition = facade.GetMultiLevelPartition(); - BOOST_ASSERT(forward_heap.Empty() || forward_heap.MinKey() < INVALID_EDGE_WEIGHT); - BOOST_ASSERT(reverse_heap.Empty() || reverse_heap.MinKey() < INVALID_EDGE_WEIGHT); + BOOST_ASSERT(!forward_heap.Empty() && forward_heap.MinKey() < INVALID_EDGE_WEIGHT); + BOOST_ASSERT(!reverse_heap.Empty() && reverse_heap.MinKey() < INVALID_EDGE_WEIGHT); // run two-Target Dijkstra routing step. NodeID middle = SPECIAL_NODEID; EdgeWeight weight = weight_upper_bound; - - EdgeWeight forward_heap_min = 0; - if (!forward_heap.Empty()) - forward_heap_min = forward_heap.MinKey(); - EdgeWeight reverse_heap_min = 0; - if (!reverse_heap.Empty()) - reverse_heap_min = reverse_heap.MinKey(); - + EdgeWeight forward_heap_min = forward_heap.MinKey(); + EdgeWeight reverse_heap_min = reverse_heap.MinKey(); while (forward_heap.Size() + reverse_heap.Size() > 0 && forward_heap_min + reverse_heap_min < weight) { @@ -662,7 +657,11 @@ double getNetworkDistance(SearchEngineData &engine_working_data, const PhantomNode &target_phantom, EdgeWeight weight_upper_bound = INVALID_EDGE_WEIGHT) { + forward_heap.Clear(); + reverse_heap.Clear(); + const PhantomNodes phantom_nodes{source_phantom, target_phantom}; + insertNodesInHeaps(forward_heap, reverse_heap, phantom_nodes); EdgeWeight weight = INVALID_EDGE_WEIGHT; std::vector unpacked_nodes; @@ -681,22 +680,11 @@ double getNetworkDistance(SearchEngineData &engine_working_data, return std::numeric_limits::max(); } - EdgeDistance distance = 0; + std::vector unpacked_path; - if (!unpacked_nodes.empty()) - { - distance = std::accumulate(unpacked_nodes.begin(), - std::prev(unpacked_nodes.end()), - EdgeDistance{0}, - [&](const EdgeDistance distance, const auto node_id) { - return distance + computeEdgeDistance(facade, node_id); - }); - } - - distance = adjustPathDistanceToPhantomNodes( - unpacked_nodes, phantom_nodes.source_phantom, phantom_nodes.target_phantom, distance); + annotatePath(facade, phantom_nodes, unpacked_nodes, unpacked_edges, unpacked_path); - return distance; + return getPathDistance(facade, unpacked_path, source_phantom, target_phantom); } } // namespace mld diff --git a/include/util/coordinate_calculation.hpp b/include/util/coordinate_calculation.hpp index 884169e4cc3..c946842a23e 100644 --- a/include/util/coordinate_calculation.hpp +++ b/include/util/coordinate_calculation.hpp @@ -23,6 +23,9 @@ namespace detail { const constexpr double DEGREE_TO_RAD = 0.017453292519943295769236907684886; const constexpr double RAD_TO_DEGREE = 1. / DEGREE_TO_RAD; +// earth radius varies between 6,356.750-6,378.135 km (3,949.901-3,963.189mi) +// The IUGG value for the equatorial radius is 6378.137 km (3963.19 miles) +const constexpr long double EARTH_RADIUS = 6372797.560856; inline double degToRad(const double degree) { diff --git a/src/engine/routing_algorithms/many_to_many_ch.cpp b/src/engine/routing_algorithms/many_to_many_ch.cpp index 496bada8fad..8ee02b5ec92 100644 --- a/src/engine/routing_algorithms/many_to_many_ch.cpp +++ b/src/engine/routing_algorithms/many_to_many_ch.cpp @@ -240,12 +240,74 @@ void calculateDistances(typename SearchEngineData::ManyToManyQuer } if (!packed_leg.empty()) { - EdgeDistance annotation = + auto annotation = ch::calculateEBGNodeAnnotations(facade, packed_leg.begin(), packed_leg.end()); - annotation = adjustPathDistanceToPhantomNodes( - packed_leg, source_phantom, target_phantom, annotation); distances_table[row_index * number_of_targets + column_index] = annotation; + + // check the direction of travel to figure out how to calculate the offset to/from + // the source/target + if (source_phantom.forward_segment_id.id == packed_leg.front()) + { + // ............ <-- calculateEGBAnnotation returns distance from 0 to 3 + // -->s <-- subtract offset to start at source + // ......... <-- want this distance as result + // entry 0---1---2---3--- <-- 3 is exit node + EdgeDistance offset = source_phantom.GetForwardDistance(); + distances_table[row_index * number_of_targets + column_index] -= offset; + } + else if (source_phantom.reverse_segment_id.id == packed_leg.front()) + { + // ............ <-- calculateEGBAnnotation returns distance from 0 to 3 + // s<------- <-- subtract offset to start at source + // ... <-- want this distance + // entry 0---1---2---3 <-- 3 is exit node + EdgeDistance offset = source_phantom.GetReverseDistance(); + distances_table[row_index * number_of_targets + column_index] -= offset; + } + if (target_phantom.forward_segment_id.id == packed_leg.back()) + { + // ............ <-- calculateEGBAnnotation returns distance from 0 to 3 + // ++>t <-- add offset to get to target + // ................ <-- want this distance as result + // entry 0---1---2---3--- <-- 3 is exit node + EdgeDistance offset = target_phantom.GetForwardDistance(); + distances_table[row_index * number_of_targets + column_index] += offset; + } + else if (target_phantom.reverse_segment_id.id == packed_leg.back()) + { + // ............ <-- calculateEGBAnnotation returns distance from 0 to 3 + // <++t <-- add offset to get from target + // ................ <-- want this distance as result + // entry 0---1---2---3--- <-- 3 is exit node + EdgeDistance offset = target_phantom.GetReverseDistance(); + distances_table[row_index * number_of_targets + column_index] += offset; + } + } + else + { + // there is no shortcut to unpack. source and target are on the same EBG Node. + // if the offset of the target is greater than the offset of the source, subtract it + if (target_phantom.GetForwardDistance() > source_phantom.GetForwardDistance()) + { + // --------->t <-- offsets + // ->s <-- subtract source offset from target offset + // ......... <-- want this distance as result + // entry 0---1---2---3--- <-- 3 is exit node + EdgeDistance offset = + target_phantom.GetForwardDistance() - source_phantom.GetForwardDistance(); + distances_table[row_index * number_of_targets + column_index] = offset; + } + else + { + // s<--- <-- offsets + // t<--------- <-- subtract source offset from target offset + // ...... <-- want this distance as result + // entry 0---1---2---3--- <-- 3 is exit node + EdgeDistance offset = + target_phantom.GetReverseDistance() - source_phantom.GetReverseDistance(); + distances_table[row_index * number_of_targets + column_index] = offset; + } } packed_leg.clear(); } diff --git a/src/engine/routing_algorithms/map_matching.cpp b/src/engine/routing_algorithms/map_matching.cpp index 695ec5778c6..7d1b75901a5 100644 --- a/src/engine/routing_algorithms/map_matching.cpp +++ b/src/engine/routing_algorithms/map_matching.cpp @@ -227,9 +227,6 @@ SubMatchingList mapMatching(SearchEngineData &engine_working_data, { continue; } - forward_heap.Clear(); - const auto &source_phantom = prev_unbroken_timestamps_list[s].phantom_node; - insertSourceInHeap(forward_heap, source_phantom); for (const auto s_prime : util::irange(0UL, current_viterbi.size())) { @@ -240,19 +237,14 @@ SubMatchingList mapMatching(SearchEngineData &engine_working_data, continue; } - reverse_heap.Clear(); - const auto &target_phantom = current_timestamps_list[s_prime].phantom_node; - insertTargetInHeap(reverse_heap, target_phantom); - - double network_distance = getNetworkDistance(engine_working_data, - facade, - forward_heap, - reverse_heap, - source_phantom, - target_phantom, - weight_upper_bound); - - network_distance = std::round(network_distance * 10) / 10; + double network_distance = + getNetworkDistance(engine_working_data, + facade, + forward_heap, + reverse_heap, + prev_unbroken_timestamps_list[s].phantom_node, + current_timestamps_list[s_prime].phantom_node, + weight_upper_bound); // get distance diff between loc1/2 and locs/s_prime const auto d_t = std::abs(network_distance - haversine_distance); diff --git a/src/engine/routing_algorithms/routing_base.cpp b/src/engine/routing_algorithms/routing_base.cpp index 472a8cc9e59..fb01472bbaa 100644 --- a/src/engine/routing_algorithms/routing_base.cpp +++ b/src/engine/routing_algorithms/routing_base.cpp @@ -33,79 +33,6 @@ bool needsLoopBackwards(const PhantomNodes &phantoms) return needsLoopBackwards(phantoms.source_phantom, phantoms.target_phantom); } -EdgeDistance adjustPathDistanceToPhantomNodes(const std::vector &path, - const PhantomNode &source_phantom, - const PhantomNode &target_phantom, - const EdgeDistance uncorrected_distance) -{ - EdgeDistance distance = uncorrected_distance; - if (!path.empty()) - { - - // check the direction of travel to figure out how to calculate the offset to/from - // the source/target - if (source_phantom.forward_segment_id.id == path.front()) - { - // ............ <-- calculateEGBAnnotation returns distance from 0 to 3 - // -->s <-- subtract offset to start at source - // ......... <-- want this distance as result - // entry 0---1---2---3--- <-- 3 is exit node - distance -= source_phantom.GetForwardDistance(); - } - else if (source_phantom.reverse_segment_id.id == path.front()) - { - // ............ <-- calculateEGBAnnotation returns distance from 0 to 3 - // s<------- <-- subtract offset to start at source - // ... <-- want this distance - // entry 0---1---2---3 <-- 3 is exit node - distance -= source_phantom.GetReverseDistance(); - } - if (target_phantom.forward_segment_id.id == path.back()) - { - // ............ <-- calculateEGBAnnotation returns distance from 0 to 3 - // ++>t <-- add offset to get to target - // ................ <-- want this distance as result - // entry 0---1---2---3--- <-- 3 is exit node - distance += target_phantom.GetForwardDistance(); - } - else if (target_phantom.reverse_segment_id.id == path.back()) - { - // ............ <-- calculateEGBAnnotation returns distance from 0 to 3 - // <++t <-- add offset to get from target - // ................ <-- want this distance as result - // entry 0---1---2---3--- <-- 3 is exit node - distance += target_phantom.GetReverseDistance(); - } - } - else - { - // there is no shortcut to unpack. source and target are on the same EBG Node. - // if the offset of the target is greater than the offset of the source, subtract it - if (target_phantom.GetForwardDistance() > source_phantom.GetForwardDistance()) - { - // --------->t <-- offsets - // ->s <-- subtract source offset from target offset - // ......... <-- want this distance as result - // entry 0---1---2---3--- <-- 3 is exit node - distance = target_phantom.GetForwardDistance() - source_phantom.GetForwardDistance(); - } - else - { - // s<--- <-- offsets - // t<--------- <-- subtract source offset from target offset - // ...... <-- want this distance as result - // entry 0---1---2---3--- <-- 3 is exit node - distance = target_phantom.GetReverseDistance() - source_phantom.GetReverseDistance(); - } - } - - BOOST_ASSERT_MSG(distance >= 0 || distance > -1.0f, - "Distance correction generated negative number"); - // guard against underflow errors caused by rounding - distance = std::max(EdgeDistance{0}, distance); - return distance; -} - } // namespace routing_algorithms } // namespace engine } // namespace osrm diff --git a/src/engine/routing_algorithms/routing_base_ch.cpp b/src/engine/routing_algorithms/routing_base_ch.cpp index d118f86f464..695ebe9234a 100644 --- a/src/engine/routing_algorithms/routing_base_ch.cpp +++ b/src/engine/routing_algorithms/routing_base_ch.cpp @@ -100,7 +100,7 @@ void search(SearchEngineData & /*engine_working_data*/, const PhantomNodes & /*phantom_nodes*/, const EdgeWeight weight_upper_bound) { - if (forward_heap.Empty() && reverse_heap.Empty()) + if (forward_heap.Empty() || reverse_heap.Empty()) { weight = INVALID_EDGE_WEIGHT; return; @@ -110,14 +110,10 @@ void search(SearchEngineData & /*engine_working_data*/, weight = weight_upper_bound; // get offset to account for offsets on phantom nodes on compressed edges - EdgeWeight min_edge_offset = 0; - if (forward_heap.Size() > 0) - { - min_edge_offset = std::min(min_edge_offset, forward_heap.MinKey()); - BOOST_ASSERT(min_edge_offset <= 0); - } + const auto min_edge_offset = std::min(0, forward_heap.MinKey()); + BOOST_ASSERT(min_edge_offset <= 0); // we only every insert negative offsets for nodes in the forward heap - BOOST_ASSERT(reverse_heap.Empty() || reverse_heap.MinKey() >= 0); + BOOST_ASSERT(reverse_heap.MinKey() >= 0); // run two-Target Dijkstra routing step. while (0 < (forward_heap.Size() + reverse_heap.Size())) @@ -180,6 +176,11 @@ double getNetworkDistance(SearchEngineData &engine_working_data, const PhantomNode &target_phantom, EdgeWeight weight_upper_bound) { + forward_heap.Clear(); + reverse_heap.Clear(); + + insertNodesInHeaps(forward_heap, reverse_heap, {source_phantom, target_phantom}); + EdgeWeight weight = INVALID_EDGE_WEIGHT; std::vector packed_path; search(engine_working_data, @@ -198,31 +199,14 @@ double getNetworkDistance(SearchEngineData &engine_working_data, return std::numeric_limits::max(); } - EdgeDistance distance = 0; - - std::vector unpacked_nodes; - unpacked_nodes.reserve(packed_path.size()); - if (!packed_path.empty()) - { - unpacked_nodes.push_back(packed_path.front()); - unpackPath( - facade, packed_path.begin(), packed_path.end(), [&](const auto &edge, const auto &) { - BOOST_ASSERT(edge.first == unpacked_nodes.back()); - unpacked_nodes.push_back(edge.second); - }); - - distance = std::accumulate(unpacked_nodes.begin(), - std::prev(unpacked_nodes.end()), - EdgeDistance{0}, - [&](const EdgeDistance distance, const auto node_id) { - return distance + computeEdgeDistance(facade, node_id); - }); - } - - distance = - adjustPathDistanceToPhantomNodes(unpacked_nodes, source_phantom, target_phantom, distance); + std::vector unpacked_path; + unpackPath(facade, + packed_path.begin(), + packed_path.end(), + {source_phantom, target_phantom}, + unpacked_path); - return distance; + return getPathDistance(facade, unpacked_path, source_phantom, target_phantom); } } // namespace ch diff --git a/src/util/coordinate_calculation.cpp b/src/util/coordinate_calculation.cpp index eb852aa3006..cb9adb10a9b 100644 --- a/src/util/coordinate_calculation.cpp +++ b/src/util/coordinate_calculation.cpp @@ -22,11 +22,6 @@ namespace coordinate_calculation namespace { - -// earth radius varies between 6,356.750-6,378.135 km (3,949.901-3,963.189mi) -// The IUGG value for the equatorial radius is 6378.137 km (3963.19 miles) -const constexpr double EARTH_RADIUS = 6372797.560856; - class CheapRulerContainer { public: @@ -117,7 +112,7 @@ double haversineDistance(const Coordinate coordinate_1, const Coordinate coordin const double aharv = std::pow(std::sin(dlat / 2.0), 2.0) + std::cos(dlat1) * std::cos(dlat2) * std::pow(std::sin(dlong / 2.), 2); const double charv = 2. * std::atan2(std::sqrt(aharv), std::sqrt(1.0 - aharv)); - return EARTH_RADIUS * charv; + return detail::EARTH_RADIUS * charv; } double greatCircleDistance(const Coordinate coordinate_1, const Coordinate coordinate_2) @@ -138,7 +133,7 @@ double greatCircleDistance(const Coordinate coordinate_1, const Coordinate coord const double x_value = (float_lon2 - float_lon1) * std::cos((float_lat1 + float_lat2) / 2.0); const double y_value = float_lat2 - float_lat1; - return std::hypot(x_value, y_value) * EARTH_RADIUS; + return std::hypot(x_value, y_value) * detail::EARTH_RADIUS; } double perpendicularDistance(const Coordinate segment_source, From 17e19663bad71814a785a875127c813c195fe52d Mon Sep 17 00:00:00 2001 From: Kajari Ghosh Date: Thu, 6 Sep 2018 13:02:25 -0400 Subject: [PATCH 26/26] rc in travis, changelog and package.json update changelog to include profile changes bump version to rc2 --- .travis.yml | 1 + CHANGELOG.md | 9 +++++++-- package.json | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3878a1415ca..45f1505d59d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,7 @@ notifications: branches: only: - master + - "5.19" # enable building tags - /^v\d+\.\d+(\.\d+)?(-\S*)?$/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c979444dc7..aa0bc5cc884 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,14 @@ -# UNRELEASED +# 5.19.0 - Changes from 5.18.0: - Optimizations: - - CHANGED: Map matching is now almost twice as fast. [#5060](https://github.com/Project-OSRM/osrm-backend/pull/5060) - CHANGED: Use Grisu2 for serializing floating point numbers. [#5188](https://github.com/Project-OSRM/osrm-backend/pull/5188) - ADDED: Node bindings can return pre-rendered JSON buffer. [#5189](https://github.com/Project-OSRM/osrm-backend/pull/5189) + - Profiles: + - CHANGED: Bicycle profile now blacklists barriers instead of whitelisting them [#5076 +](https://github.com/Project-OSRM/osrm-backend/pull/5076/) + - CHANGED: Foot profile now blacklists barriers instead of whitelisting them [#5077 +](https://github.com/Project-OSRM/osrm-backend/pull/5077/) + - CHANGED: Support maxlength and maxweight in car profile [#5101](https://github.com/Project-OSRM/osrm-backend/pull/5101] - Bugfixes: - FIXED: collapsing of ExitRoundabout instructions [#5114](https://github.com/Project-OSRM/osrm-backend/issues/5114) - Misc: diff --git a/package.json b/package.json index c33fa4e2826..6f95cd55382 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "osrm", - "version": "5.18.0-latest.1", + "version": "5.19.0", "private": false, "description": "The Open Source Routing Machine is a high performance routing engine written in C++14 designed to run on OpenStreetMap data.", "dependencies": {