Merge branch 'master' into replace_boost_filesystem

This commit is contained in:
Siarhei Fedartsou 2024-06-19 19:18:05 +02:00
commit a1d34196cd
17 changed files with 875 additions and 180 deletions

View File

@ -645,8 +645,10 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
GITHUB_REPOSITORY: ${{ github.repository }}
RUN_BIG_BENCHMARK: ${{ contains(github.event.pull_request.labels.*.name, 'Performance') }}
steps:
- name: Enable data.osm.pbf cache
if: ${{ ! env.RUN_BIG_BENCHMARK }}
uses: actions/cache@v4
with:
path: ~/data.osm.pbf
@ -678,10 +680,18 @@ jobs:
sudo apt-get update -y && sudo apt-get install ccache
- name: Prepare data
run: |
if [ ! -f "~/data.osm.pbf" ]; then
wget http://download.geofabrik.de/europe/germany/berlin-latest.osm.pbf -O ~/data.osm.pbf
if [ "$RUN_BIG_BENCHMARK" = "true" ]; then
rm -rf ~/data.osm.pbf
wget http://download.geofabrik.de/europe/poland-latest.osm.pbf -O ~/data.osm.pbf --quiet
gunzip -c ./pr/test/data/poland_gps_traces.csv.gz > ~/gps_traces.csv
else
if [ ! -f "~/data.osm.pbf" ]; then
wget http://download.geofabrik.de/europe/germany/berlin-latest.osm.pbf -O ~/data.osm.pbf
else
echo "Using cached data.osm.pbf"
fi
gunzip -c ./pr/test/data/berlin_gps_traces.csv.gz > ~/gps_traces.csv
fi
gunzip -c ./pr/test/data/berlin_gps_traces.csv.gz > ~/gps_traces.csv
- name: Prepare environment
run: |
echo "CCACHE_DIR=$HOME/.ccache" >> $GITHUB_ENV

View File

@ -24,6 +24,13 @@
- NodeJS:
- CHANGED: Use node-api instead of NAN. [#6452](https://github.com/Project-OSRM/osrm-backend/pull/6452)
- Misc:
- CHANGED: Apply micro-optimisation for Table & Trip APIs. [#6949](https://github.com/Project-OSRM/osrm-backend/pull/6949)
- CHANGED: Apply micro-optimisation for Route API. [#6948](https://github.com/Project-OSRM/osrm-backend/pull/6948)
- CHANGED: Apply micro-optimisation for Match API. [#6945](https://github.com/Project-OSRM/osrm-backend/pull/6945)
- CHANGED: Apply micro-optimisation for Nearest API. [#6944](https://github.com/Project-OSRM/osrm-backend/pull/6944)
- CHANGED: Avoid copy of intersection in totalTurnAngle. [#6938](https://github.com/Project-OSRM/osrm-backend/pull/6938)
- CHANGED: Use std::unordered_map::emplace instead of operator[] when producing JSONs. [#6936](https://github.com/Project-OSRM/osrm-backend/pull/6936)
- CHANGED: Avoid copy of vectors in MakeRoute function. [#6939](https://github.com/Project-OSRM/osrm-backend/pull/6939)
- FIXED: Fix bugprone-unused-return-value clang-tidy warning. [#6934](https://github.com/Project-OSRM/osrm-backend/pull/6934)
- FIXED: Fix performance-noexcept-move-constructor clang-tidy warning. [#6931](https://github.com/Project-OSRM/osrm-backend/pull/6933)
- FIXED: Fix performance-noexcept-swap clang-tidy warning. [#6931](https://github.com/Project-OSRM/osrm-backend/pull/6931)

View File

@ -330,20 +330,12 @@ if(ENABLE_CONAN)
set(CONAN_BOOST_VERSION "1.85.0@#14265ec82b25d91305bbb3b30d3357f8")
set(CONAN_BZIP2_VERSION "1.0.8@#d1b2d5816f25865acf978501dff1f897")
set(CONAN_EXPAT_VERSION "2.2.10@#916908d4a570ad839edd25322c3268cd")
set(CONAN_LUA_VERSION "5.4.4@#3ec62efc37cd0a5d80b9e5cb35277360")
set(CONAN_TBB_VERSION "2021.3.0@#507ec17cbd51a84167e143b20d170eea")
set(CONAN_EXPAT_VERSION "2.6.2@#2d385d0d50eb5561006a7ff9e356656b")
set(CONAN_LUA_VERSION "5.4.6@#658d6089093cf01992c2737ab2e96763")
set(CONAN_TBB_VERSION "2021.12.0@#e56e5b44be8d690530585dd3634c0106")
set(CONAN_SYSTEM_INCLUDES ON)
# TODO:
# if we link TBB dynamically osrm-extract.exe finishes on the first access to any TBB symbol
# with exit code = -1073741515, which means that program cannot load required DLL.
if (MSVC)
set(TBB_SHARED False)
else()
set(TBB_SHARED True)
endif()
set(CONAN_ARGS
REQUIRES
@ -357,7 +349,6 @@ if(ENABLE_CONAN)
KEEP_RPATHS
NO_OUTPUT_DIRS
OPTIONS boost:filesystem_version=3 # https://stackoverflow.com/questions/73392648/error-with-boost-filesystem-version-in-cmake
onetbb:shared=${TBB_SHARED}
boost:without_stacktrace=True # Apple Silicon cross-compilation fails without it
BUILD missing
)

64
docker/Dockerfile-alpine Normal file
View File

@ -0,0 +1,64 @@
FROM alpine:3.20.0 as alpine-mimalloc
RUN apk add --no-cache mimalloc
ENV LD_PRELOAD=/usr/lib/libmimalloc.so.2
ENV MIMALLOC_LARGE_OS_PAGES=1
FROM alpine-mimalloc as builder
ARG DOCKER_TAG
ARG BUILD_CONCURRENCY
RUN mkdir -p /src && mkdir -p /opt
RUN apk add --no-cache \
cmake make git clang libbz2 libxml2 \
boost-dev boost-program_options boost-filesystem boost-iostreams boost-thread \
lua5.4-dev onetbb-dev expat-dev
COPY . /src
WORKDIR /src
RUN NPROC=${BUILD_CONCURRENCY:-$(nproc)} && \
echo "Building OSRM ${DOCKER_TAG}" && \
git show --format="%H" | head -n1 > /opt/OSRM_GITSHA && \
echo "Building OSRM gitsha $(cat /opt/OSRM_GITSHA)" && \
mkdir -p build && \
cd build && \
BUILD_TYPE="Release" && \
ENABLE_ASSERTIONS="Off" && \
BUILD_TOOLS="Off" && \
case ${DOCKER_TAG} in *"-debug"*) BUILD_TYPE="Debug";; esac && \
case ${DOCKER_TAG} in *"-assertions"*) BUILD_TYPE="RelWithDebInfo" && ENABLE_ASSERTIONS="On" && BUILD_TOOLS="On";; esac && \
echo "Building ${BUILD_TYPE} with ENABLE_ASSERTIONS=${ENABLE_ASSERTIONS} BUILD_TOOLS=${BUILD_TOOLS}" && \
cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DENABLE_ASSERTIONS=${ENABLE_ASSERTIONS} -DBUILD_TOOLS=${BUILD_TOOLS} -DENABLE_LTO=On && \
make -j${NPROC} install && \
cd ../profiles && \
cp -r * /opt && \
strip /usr/local/bin/* && \
rm -rf /src
# Multistage build to reduce image size - https://docs.docker.com/engine/userguide/eng-image/multistage-build/#use-multi-stage-builds
# Only the content below ends up in the image, this helps remove /src from the image (which is large)
FROM alpine-mimalloc as runstage
COPY --from=builder /usr/local /usr/local
COPY --from=builder /opt /opt
RUN apk add --no-cache \
boost-program_options boost-regex \
boost-date_time boost-chrono boost-filesystem \
boost-iostreams boost-system boost-thread \
expat lua5.4 onetbb && \
ldconfig /usr/local/lib
RUN /usr/local/bin/osrm-extract --help && \
/usr/local/bin/osrm-routed --help && \
/usr/local/bin/osrm-contract --help && \
/usr/local/bin/osrm-partition --help && \
/usr/local/bin/osrm-customize --help
WORKDIR /opt
EXPOSE 5000

6
docker/hooks/build Normal file → Executable file
View File

@ -6,4 +6,8 @@
# ensure that "COPY . /src" is referring to the repo root, not the directory
# that contains the Dockerfile.
# This script gets executed with a pwd of wherever the Dockerfile is.
docker build --build-arg BUILD_CONCURRENCY=${CONCURRENCY:-1} --build-arg DOCKER_TAG=${DOCKER_TAG} -t $IMAGE_NAME -f Dockerfile ..
DOCKER_BUILD="docker build --build-arg BUILD_CONCURRENCY=${CONCURRENCY} --build-arg DOCKER_TAG=${DOCKER_TAG:?unset} -t ${IMAGE_NAME:?unset} -f"
$DOCKER_BUILD Dockerfile ..
$DOCKER_BUILD Dockerfile-alpine ..

View File

@ -77,19 +77,19 @@ class MatchAPI final : public RouteAPI
sub_routes[index].unpacked_path_segments,
sub_routes[index].source_traversed_in_reverse,
sub_routes[index].target_traversed_in_reverse);
route.values["confidence"] = sub_matchings[index].confidence;
routes.values.push_back(std::move(route));
route.values.emplace("confidence", sub_matchings[index].confidence);
routes.values.emplace_back(std::move(route));
}
if (!parameters.skip_waypoints)
{
response.values["tracepoints"] = MakeTracepoints(sub_matchings);
response.values.emplace("tracepoints", MakeTracepoints(sub_matchings));
}
response.values["matchings"] = std::move(routes);
response.values["code"] = "Ok";
response.values.emplace("matchings", std::move(routes));
response.values.emplace("code", "Ok");
auto data_timestamp = facade.GetTimestamp();
if (!data_timestamp.empty())
{
response.values["data_version"] = data_timestamp;
response.values.emplace("data_version", data_timestamp);
}
}
@ -132,13 +132,13 @@ class MatchAPI final : public RouteAPI
if (tidy_result.can_be_removed[trace_index])
{
waypoints.push_back(fbresult::WaypointBuilder(fb_result).Finish());
waypoints.emplace_back(fbresult::WaypointBuilder(fb_result).Finish());
continue;
}
auto matching_index = trace_idx_to_matching_idx[trace_index];
if (matching_index.NotMatched())
{
waypoints.push_back(fbresult::WaypointBuilder(fb_result).Finish());
waypoints.emplace_back(fbresult::WaypointBuilder(fb_result).Finish());
continue;
}
const auto &phantom =
@ -165,7 +165,7 @@ class MatchAPI final : public RouteAPI
{
waypoint->add_waypoint_index(matching_index.point_index);
}
waypoints.push_back(waypoint->Finish());
waypoints.emplace_back(waypoint->Finish());
}
return fb_result.CreateVector(waypoints);
@ -186,23 +186,23 @@ class MatchAPI final : public RouteAPI
{
if (tidy_result.can_be_removed[trace_index])
{
waypoints.values.push_back(util::json::Null());
waypoints.values.emplace_back(util::json::Null());
continue;
}
auto matching_index = trace_idx_to_matching_idx[trace_index];
if (matching_index.NotMatched())
{
waypoints.values.push_back(util::json::Null());
waypoints.values.emplace_back(util::json::Null());
continue;
}
const auto &phantom =
sub_matchings[matching_index.sub_matching_index].nodes[matching_index.point_index];
auto waypoint = BaseAPI::MakeWaypoint({phantom});
waypoint.values["matchings_index"] = matching_index.sub_matching_index;
waypoint.values["waypoint_index"] = matching_index.point_index;
waypoint.values["alternatives_count"] =
sub_matchings[matching_index.sub_matching_index]
.alternatives_count[matching_index.point_index];
waypoint.values.emplace("matchings_index", matching_index.sub_matching_index);
waypoint.values.emplace("waypoint_index", matching_index.point_index);
waypoint.values.emplace("alternatives_count",
sub_matchings[matching_index.sub_matching_index]
.alternatives_count[matching_index.point_index]);
// waypoint indices need to be adjusted if route legs were collapsed
// waypoint parameter assumes there is only one match object
if (!parameters.waypoints.empty())
@ -217,7 +217,7 @@ class MatchAPI final : public RouteAPI
waypoint.values["waypoint_index"] = util::json::Null();
}
}
waypoints.values.push_back(std::move(waypoint));
waypoints.values.emplace_back(std::move(waypoint));
}
return waypoints;

View File

@ -100,23 +100,23 @@ class NearestAPI final : public BaseAPI
auto waypoint = MakeWaypoint({phantom_node});
util::json::Array nodes;
nodes.values.reserve(2);
auto node_values = MakeNodes(phantom_node);
nodes.values.push_back(node_values.first);
nodes.values.push_back(node_values.second);
waypoint.values["nodes"] = std::move(nodes);
nodes.values.emplace_back(node_values.first);
nodes.values.emplace_back(node_values.second);
waypoint.values.emplace("nodes", std::move(nodes));
return waypoint;
});
response.values["waypoints"] = std::move(waypoints);
response.values.emplace("waypoints", std::move(waypoints));
}
response.values["code"] = "Ok";
response.values.emplace("code", "Ok");
auto data_timestamp = facade.GetTimestamp();
if (!data_timestamp.empty())
{
response.values["data_version"] = data_timestamp;
response.values.emplace("data_version", data_timestamp);
}
}

View File

@ -110,14 +110,14 @@ class RouteAPI : public BaseAPI
if (!parameters.skip_waypoints)
{
response.values["waypoints"] = BaseAPI::MakeWaypoints(waypoint_candidates);
response.values.emplace("waypoints", BaseAPI::MakeWaypoints(waypoint_candidates));
}
response.values["routes"] = std::move(jsRoutes);
response.values["code"] = "Ok";
response.values.emplace("routes", std::move(jsRoutes));
response.values.emplace("code", "Ok");
auto data_timestamp = facade.GetTimestamp();
if (!data_timestamp.empty())
{
response.values["data_version"] = data_timestamp;
response.values.emplace("data_version", data_timestamp);
}
}
@ -340,8 +340,8 @@ class RouteAPI : public BaseAPI
unpacked_path_segments,
source_traversed_in_reverse,
target_traversed_in_reverse);
std::vector<guidance::RouteLeg> legs = legs_info.first;
std::vector<guidance::LegGeometry> leg_geometries = legs_info.second;
std::vector<guidance::RouteLeg> &legs = legs_info.first;
std::vector<guidance::LegGeometry> &leg_geometries = legs_info.second;
auto route = guidance::assembleRoute(legs);
// Fill legs
@ -716,8 +716,8 @@ class RouteAPI : public BaseAPI
unpacked_path_segments,
source_traversed_in_reverse,
target_traversed_in_reverse);
std::vector<guidance::RouteLeg> legs = legs_info.first;
std::vector<guidance::LegGeometry> leg_geometries = legs_info.second;
std::vector<guidance::RouteLeg> &legs = legs_info.first;
std::vector<guidance::LegGeometry> &leg_geometries = legs_info.second;
auto route = guidance::assembleRoute(legs);
boost::optional<util::json::Value> json_overview =
@ -784,49 +784,57 @@ class RouteAPI : public BaseAPI
if (requested_annotations & RouteParameters::AnnotationsType::Speed)
{
double prev_speed = 0;
annotation.values["speed"] = GetAnnotations(
leg_geometry,
[&prev_speed](const guidance::LegGeometry::Annotation &anno)
{
if (anno.duration < std::numeric_limits<double>::min())
{
return prev_speed;
}
else
{
auto speed = std::round(anno.distance / anno.duration * 10.) / 10.;
prev_speed = speed;
return util::json::clamp_float(speed);
}
});
annotation.values.emplace(
"speed",
GetAnnotations(leg_geometry,
[&prev_speed](const guidance::LegGeometry::Annotation &anno)
{
if (anno.duration < std::numeric_limits<double>::min())
{
return prev_speed;
}
else
{
auto speed =
std::round(anno.distance / anno.duration * 10.) /
10.;
prev_speed = speed;
return util::json::clamp_float(speed);
}
}));
}
if (requested_annotations & RouteParameters::AnnotationsType::Duration)
{
annotation.values["duration"] =
annotation.values.emplace(
"duration",
GetAnnotations(leg_geometry,
[](const guidance::LegGeometry::Annotation &anno)
{ return anno.duration; });
{ return anno.duration; }));
}
if (requested_annotations & RouteParameters::AnnotationsType::Distance)
{
annotation.values["distance"] =
annotation.values.emplace(
"distance",
GetAnnotations(leg_geometry,
[](const guidance::LegGeometry::Annotation &anno)
{ return anno.distance; });
{ return anno.distance; }));
}
if (requested_annotations & RouteParameters::AnnotationsType::Weight)
{
annotation.values["weight"] = GetAnnotations(
leg_geometry,
[](const guidance::LegGeometry::Annotation &anno) { return anno.weight; });
annotation.values.emplace(
"weight",
GetAnnotations(leg_geometry,
[](const guidance::LegGeometry::Annotation &anno)
{ return anno.weight; }));
}
if (requested_annotations & RouteParameters::AnnotationsType::Datasources)
{
annotation.values["datasources"] =
annotation.values.emplace(
"datasources",
GetAnnotations(leg_geometry,
[](const guidance::LegGeometry::Annotation &anno)
{ return anno.datasource; });
{ return anno.datasource; }));
}
if (requested_annotations & RouteParameters::AnnotationsType::Nodes)
{
@ -837,7 +845,7 @@ class RouteAPI : public BaseAPI
nodes.values.push_back(
static_cast<std::uint64_t>(facade.GetOSMNodeIDOfNode(node_id)));
}
annotation.values["nodes"] = std::move(nodes);
annotation.values.emplace("nodes", std::move(nodes));
}
// Add any supporting metadata, if needed
if (requested_annotations & RouteParameters::AnnotationsType::Datasources)
@ -853,8 +861,8 @@ class RouteAPI : public BaseAPI
break;
datasource_names.values.push_back(std::string(facade.GetDatasourceName(i)));
}
metadata.values["datasource_names"] = datasource_names;
annotation.values["metadata"] = metadata;
metadata.values.emplace("datasource_names", datasource_names);
annotation.values.emplace("metadata", metadata);
}
annotations.push_back(std::move(annotation));

View File

@ -179,7 +179,7 @@ class TableAPI final : public BaseAPI
{
if (!parameters.skip_waypoints)
{
response.values["sources"] = MakeWaypoints(candidates);
response.values.emplace("sources", MakeWaypoints(candidates));
}
number_of_sources = candidates.size();
}
@ -187,7 +187,7 @@ class TableAPI final : public BaseAPI
{
if (!parameters.skip_waypoints)
{
response.values["sources"] = MakeWaypoints(candidates, parameters.sources);
response.values.emplace("sources", MakeWaypoints(candidates, parameters.sources));
}
}
@ -195,7 +195,7 @@ class TableAPI final : public BaseAPI
{
if (!parameters.skip_waypoints)
{
response.values["destinations"] = MakeWaypoints(candidates);
response.values.emplace("destinations", MakeWaypoints(candidates));
}
number_of_destinations = candidates.size();
}
@ -203,34 +203,37 @@ class TableAPI final : public BaseAPI
{
if (!parameters.skip_waypoints)
{
response.values["destinations"] =
MakeWaypoints(candidates, parameters.destinations);
response.values.emplace("destinations",
MakeWaypoints(candidates, parameters.destinations));
}
}
if (parameters.annotations & TableParameters::AnnotationsType::Duration)
{
response.values["durations"] =
MakeDurationTable(tables.first, number_of_sources, number_of_destinations);
response.values.emplace(
"durations",
MakeDurationTable(tables.first, number_of_sources, number_of_destinations));
}
if (parameters.annotations & TableParameters::AnnotationsType::Distance)
{
response.values["distances"] =
MakeDistanceTable(tables.second, number_of_sources, number_of_destinations);
response.values.emplace(
"distances",
MakeDistanceTable(tables.second, number_of_sources, number_of_destinations));
}
if (parameters.fallback_speed != from_alias<double>(INVALID_FALLBACK_SPEED) &&
parameters.fallback_speed > 0)
{
response.values["fallback_speed_cells"] = MakeEstimatesTable(fallback_speed_cells);
response.values.emplace("fallback_speed_cells",
MakeEstimatesTable(fallback_speed_cells));
}
response.values["code"] = "Ok";
response.values.emplace("code", "Ok");
auto data_timestamp = facade.GetTimestamp();
if (!data_timestamp.empty())
{
response.values["data_version"] = data_timestamp;
response.values.emplace("data_version", data_timestamp);
}
}

View File

@ -79,14 +79,14 @@ class TripAPI final : public RouteAPI
}
if (!parameters.skip_waypoints)
{
response.values["waypoints"] = MakeWaypoints(sub_trips, candidates);
response.values.emplace("waypoints", MakeWaypoints(sub_trips, candidates));
}
response.values["trips"] = std::move(routes);
response.values["code"] = "Ok";
response.values.emplace("trips", std::move(routes));
response.values.emplace("code", "Ok");
auto data_timestamp = facade.GetTimestamp();
if (!data_timestamp.empty())
{
response.values["data_version"] = data_timestamp;
response.values.emplace("data_version", data_timestamp);
}
}
@ -151,8 +151,8 @@ class TripAPI final : public RouteAPI
BOOST_ASSERT(!trip_index.NotUsed());
auto waypoint = BaseAPI::MakeWaypoint(candidates[input_index]);
waypoint.values["trips_index"] = trip_index.sub_trip_index;
waypoint.values["waypoint_index"] = trip_index.point_index;
waypoint.values.emplace("trips_index", trip_index.sub_trip_index);
waypoint.values.emplace("waypoint_index", trip_index.point_index);
waypoints.values.push_back(std::move(waypoint));
}

View File

@ -202,8 +202,8 @@ inline double totalTurnAngle(const RouteStep &entry_step, const RouteStep &exit_
if (entry_step.geometry_begin > exit_step.geometry_begin)
return totalTurnAngle(exit_step, entry_step);
const auto exit_intersection = exit_step.intersections.front();
const auto entry_intersection = entry_step.intersections.front();
const auto &exit_intersection = exit_step.intersections.front();
const auto &entry_intersection = entry_step.intersections.front();
if ((exit_intersection.out >= exit_intersection.bearings.size()) ||
(entry_intersection.in >= entry_intersection.bearings.size()))
return entry_intersection.bearings[entry_intersection.out];

View File

@ -4,41 +4,43 @@ import csv
import sys
import argparse
def get_osm_gps_traces(min_lon, min_lat, max_lon, max_lat):
def get_osm_gps_traces(bboxes):
url = 'https://api.openstreetmap.org/api/0.6/trackpoints'
traces = []
lon_step = 0.25
lat_step = 0.25
current_min_lon = min_lon
while current_min_lon < max_lon:
current_max_lon = min(current_min_lon + lon_step, max_lon)
for bbox in bboxes:
min_lon, min_lat, max_lon, max_lat = map(float, bbox.split(','))
current_min_lat = min_lat
while current_min_lat < max_lat:
current_max_lat = min(current_min_lat + lat_step, max_lat)
current_min_lon = min_lon
while current_min_lon < max_lon:
current_max_lon = min(current_min_lon + lon_step, max_lon)
bbox = f'{current_min_lon},{current_min_lat},{current_max_lon},{current_max_lat}'
print(f"Requesting bbox: {bbox}", file=sys.stderr)
params = {
'bbox': bbox,
'page': 0
}
headers = {
'Accept': 'application/xml'
}
response = requests.get(url, params=params, headers=headers)
if response.status_code == 200:
traces.append(response.content)
else:
print(f"Error fetching data for bbox {bbox}: {response.status_code} {response.text}", file=sys.stderr)
current_min_lat += lat_step
current_min_lon += lon_step
current_min_lat = min_lat
while current_min_lat < max_lat:
current_max_lat = min(current_min_lat + lat_step, max_lat)
bbox_str = f'{current_min_lon},{current_min_lat},{current_max_lon},{current_max_lat}'
print(f"Requesting bbox: {bbox_str}", file=sys.stderr)
params = {
'bbox': bbox_str,
'page': 0
}
headers = {
'Accept': 'application/xml'
}
response = requests.get(url, params=params, headers=headers)
if response.status_code == 200:
traces.append(response.content)
else:
print(f"Error fetching data for bbox {bbox_str}: {response.status_code} {response.text}", file=sys.stderr)
current_min_lat += lat_step
current_min_lon += lon_step
return traces
@ -68,15 +70,12 @@ def save_to_csv(data, file):
writer.writerows(data)
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Fetch and output OSM GPS traces for a given bounding box.')
parser.add_argument('min_lon', type=float, help='Minimum longitude of the bounding box')
parser.add_argument('min_lat', type=float, help='Minimum latitude of the bounding box')
parser.add_argument('max_lon', type=float, help='Maximum longitude of the bounding box')
parser.add_argument('max_lat', type=float, help='Maximum latitude of the bounding box')
parser = argparse.ArgumentParser(description='Fetch and output OSM GPS traces for given bounding boxes.')
parser.add_argument('bboxes', nargs='+', help='Bounding boxes in the format min_lon,min_lat,max_lon,max_lat')
args = parser.parse_args()
gpx_data_traces = get_osm_gps_traces(args.min_lon, args.min_lat, args.max_lon, args.max_lat)
gpx_data_traces = get_osm_gps_traces(args.bboxes)
print(f"Collected {len(gpx_data_traces)} trace segments", file=sys.stderr)
all_data = []

View File

@ -42,6 +42,12 @@ function run_benchmarks_for_folder {
measure_peak_ram_and_time "$BINARIES_FOLDER/osrm-customize $FOLDER/data.osrm" "$RESULTS_FOLDER/osrm_customize.bench"
measure_peak_ram_and_time "$BINARIES_FOLDER/osrm-contract $FOLDER/data.osrm" "$RESULTS_FOLDER/osrm_contract.bench"
for BENCH in nearest table trip route match; do
./$BENCHMARKS_FOLDER/bench "$FOLDER/data.osrm" mld ~/gps_traces.csv ${BENCH} > "$RESULTS_FOLDER/random_${BENCH}_mld.bench" || true
./$BENCHMARKS_FOLDER/bench "$FOLDER/data.osrm" ch ~/gps_traces.csv ${BENCH} > "$RESULTS_FOLDER/random_${BENCH}_ch.bench" || true
done
for ALGORITHM in ch mld; do
$BINARIES_FOLDER/osrm-routed --algorithm $ALGORITHM $FOLDER/data.osrm &
OSRM_ROUTED_PID=$!
@ -59,8 +65,6 @@ function run_benchmarks_for_folder {
kill -9 $OSRM_ROUTED_PID
done
}
run_benchmarks_for_folder $1 "${1}_results" $2

View File

@ -18,6 +18,7 @@ target_link_libraries(rtree-bench
${TBB_LIBRARIES}
${MAYBE_SHAPEFILE})
add_executable(match-bench
EXCLUDE_FROM_ALL
${MatchBenchmarkSources}
@ -35,6 +36,7 @@ add_executable(route-bench
route.cpp
$<TARGET_OBJECTS:UTIL>)
target_link_libraries(route-bench
osrm
${BOOST_BASE_LIBRARIES}
@ -42,6 +44,18 @@ target_link_libraries(route-bench
${TBB_LIBRARIES}
${MAYBE_SHAPEFILE})
add_executable(bench
EXCLUDE_FROM_ALL
bench.cpp
$<TARGET_OBJECTS:UTIL>)
target_link_libraries(bench
osrm
${BOOST_BASE_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT}
${TBB_LIBRARIES}
${MAYBE_SHAPEFILE})
add_executable(json-render-bench
EXCLUDE_FROM_ALL
json_render.cpp
@ -85,5 +99,6 @@ add_custom_target(benchmarks
packedvector-bench
match-bench
route-bench
bench
json-render-bench
alias-bench)

573
src/benchmarks/bench.cpp Normal file
View File

@ -0,0 +1,573 @@
#include "osrm/match_parameters.hpp"
#include "osrm/nearest_parameters.hpp"
#include "osrm/table_parameters.hpp"
#include "osrm/trip_parameters.hpp"
#include "engine/engine_config.hpp"
#include "util/coordinate.hpp"
#include "util/timing_util.hpp"
#include "osrm/route_parameters.hpp"
#include "osrm/coordinate.hpp"
#include "osrm/engine_config.hpp"
#include "osrm/json_container.hpp"
#include "osrm/osrm.hpp"
#include "osrm/status.hpp"
#include <boost/assert.hpp>
#include <boost/optional/optional.hpp>
#include <cstdlib>
#include <exception>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <optional>
#include <ostream>
#include <random>
#include <stdexcept>
#include <string>
#include <unordered_map>
#include <vector>
using namespace osrm;
namespace
{
class GPSTraces
{
private:
std::set<int> trackIDs;
std::unordered_map<int /* track id */, std::vector<osrm::util::Coordinate>> traces;
std::vector<osrm::util::Coordinate> coordinates;
mutable std::mt19937 gen;
public:
GPSTraces(int seed) : gen(std::random_device{}()) { gen.seed(seed); }
bool readCSV(const std::string &filename)
{
std::ifstream file(filename);
if (!file.is_open())
{
std::cerr << "Error opening file: " << filename << std::endl;
return false;
}
std::string line;
std::getline(file, line);
while (std::getline(file, line))
{
std::istringstream ss(line);
std::string token;
int trackID;
double latitude, longitude;
std::string time;
std::getline(ss, token, ',');
trackID = std::stoi(token);
std::getline(ss, token, ',');
latitude = std::stod(token);
std::getline(ss, token, ',');
longitude = std::stod(token);
// handle empty fields
if (std::getline(ss, token, ','))
{
time = token;
}
trackIDs.insert(trackID);
traces[trackID].emplace_back(osrm::util::Coordinate{
osrm::util::FloatLongitude{longitude}, osrm::util::FloatLatitude{latitude}});
coordinates.emplace_back(osrm::util::Coordinate{osrm::util::FloatLongitude{longitude},
osrm::util::FloatLatitude{latitude}});
}
file.close();
return true;
}
const osrm::util::Coordinate &getRandomCoordinate() const
{
std::uniform_int_distribution<> dis(0, coordinates.size() - 1);
return coordinates[dis(gen)];
}
const std::vector<osrm::util::Coordinate> &getRandomTrace() const
{
std::uniform_int_distribution<> dis(0, trackIDs.size() - 1);
auto it = trackIDs.begin();
std::advance(it, dis(gen));
return traces.at(*it);
}
};
class Statistics
{
public:
void push(double timeMs)
{
times.push_back(timeMs);
sorted = false;
}
double mean() { return sum() / times.size(); }
double sum()
{
double sum = 0;
for (auto time : times)
{
sum += time;
}
return sum;
}
double min() { return *std::min_element(times.begin(), times.end()); }
double max() { return *std::max_element(times.begin(), times.end()); }
double percentile(double p)
{
const auto &times = getTimes();
return times[static_cast<size_t>(p * times.size())];
}
private:
std::vector<double> getTimes()
{
if (!sorted)
{
std::sort(times.begin(), times.end());
sorted = true;
}
return times;
}
std::vector<double> times;
bool sorted = false;
};
std::ostream &operator<<(std::ostream &os, Statistics &statistics)
{
os << std::fixed << std::setprecision(2);
os << "total: " << statistics.sum() << "ms" << std::endl;
os << "avg: " << statistics.mean() << "ms" << std::endl;
os << "min: " << statistics.min() << "ms" << std::endl;
os << "max: " << statistics.max() << "ms" << std::endl;
os << "p99: " << statistics.percentile(0.99) << "ms" << std::endl;
return os;
}
void runRouteBenchmark(const OSRM &osrm, const GPSTraces &gpsTraces)
{
struct Benchmark
{
std::string name;
size_t coordinates;
RouteParameters::OverviewType overview;
bool steps = false;
std::optional<size_t> alternatives = std::nullopt;
std::optional<double> radius = std::nullopt;
};
auto run_benchmark = [&](const Benchmark &benchmark)
{
Statistics statistics;
auto NUM = 10000;
for (int i = 0; i < NUM; ++i)
{
RouteParameters params;
params.overview = benchmark.overview;
params.steps = benchmark.steps;
for (size_t i = 0; i < benchmark.coordinates; ++i)
{
params.coordinates.push_back(gpsTraces.getRandomCoordinate());
}
if (benchmark.alternatives)
{
params.alternatives = *benchmark.alternatives;
}
if (benchmark.radius)
{
params.radiuses = std::vector<boost::optional<double>>(
params.coordinates.size(), boost::make_optional(*benchmark.radius));
}
engine::api::ResultT result = json::Object();
TIMER_START(routes);
const auto rc = osrm.Route(params, result);
TIMER_STOP(routes);
statistics.push(TIMER_MSEC(routes));
auto &json_result = std::get<json::Object>(result);
if (rc != Status::Ok || json_result.values.find("routes") == json_result.values.end())
{
auto code = std::get<json::String>(json_result.values["code"]).value;
if (code != "NoSegment" && code != "NoRoute")
{
throw std::runtime_error{"Couldn't route: " + code};
}
}
}
std::cout << benchmark.name << std::endl;
std::cout << statistics << std::endl;
};
std::vector<Benchmark> benchmarks = {
{"10000 routes, 3 coordinates, no alternatives, overview=full, steps=true",
3,
RouteParameters::OverviewType::Full,
true,
std::nullopt},
{"10000 routes, 2 coordinates, no alternatives, overview=full, steps=true",
2,
RouteParameters::OverviewType::Full,
true,
std::nullopt},
{"10000 routes, 2 coordinates, 3 alternatives, overview=full, steps=true",
2,
RouteParameters::OverviewType::Full,
true,
3},
{"10000 routes, 3 coordinates, no alternatives, overview=false, steps=false",
3,
RouteParameters::OverviewType::False,
false,
std::nullopt},
{"10000 routes, 2 coordinates, no alternatives, overview=false, steps=false",
2,
RouteParameters::OverviewType::False,
false,
std::nullopt},
{"10000 routes, 2 coordinates, 3 alternatives, overview=false, steps=false",
2,
RouteParameters::OverviewType::False,
false,
3},
{"10000 routes, 3 coordinates, no alternatives, overview=false, steps=false, radius=750",
3,
RouteParameters::OverviewType::False,
false,
std::nullopt,
750},
{"10000 routes, 2 coordinates, no alternatives, overview=false, steps=false, radius=750",
2,
RouteParameters::OverviewType::False,
false,
std::nullopt,
750},
{"10000 routes, 2 coordinates, 3 alternatives, overview=false, steps=false, radius=750",
2,
RouteParameters::OverviewType::False,
false,
3,
750}
};
for (const auto &benchmark : benchmarks)
{
run_benchmark(benchmark);
}
}
void runMatchBenchmark(const OSRM &osrm, const GPSTraces &gpsTraces)
{
struct Benchmark
{
std::string name;
std::optional<size_t> radius = std::nullopt;
};
auto run_benchmark = [&](const Benchmark &benchmark)
{
Statistics statistics;
auto NUM = 1000;
for (int i = 0; i < NUM; ++i)
{
engine::api::ResultT result = json::Object();
engine::api::MatchParameters params;
params.coordinates = gpsTraces.getRandomTrace();
params.radiuses = {};
if (benchmark.radius)
{
for (size_t index = 0; index < params.coordinates.size(); ++index)
{
params.radiuses.emplace_back(*benchmark.radius);
}
}
TIMER_START(match);
const auto rc = osrm.Match(params, result);
TIMER_STOP(match);
statistics.push(TIMER_MSEC(match));
auto &json_result = std::get<json::Object>(result);
if (rc != Status::Ok ||
json_result.values.find("matchings") == json_result.values.end())
{
auto code = std::get<json::String>(json_result.values["code"]).value;
if (code != "NoSegment" && code != "NoMatch")
{
throw std::runtime_error{"Couldn't route: " + code};
}
}
}
std::cout << benchmark.name << std::endl;
std::cout << statistics << std::endl;
};
std::vector<Benchmark> benchmarks = {{"1000 matches, default radius"},
{"1000 matches, radius=10", 10},
{"1000 matches, radius=20", 20}};
for (const auto &benchmark : benchmarks)
{
run_benchmark(benchmark);
}
}
void runNearestBenchmark(const OSRM &osrm, const GPSTraces &gpsTraces)
{
struct Benchmark
{
std::string name;
std::optional<size_t> number_of_results = std::nullopt;
};
auto run_benchmark = [&](const Benchmark &benchmark)
{
Statistics statistics;
auto NUM = 10000;
for (int i = 0; i < NUM; ++i)
{
engine::api::ResultT result = json::Object();
NearestParameters params;
params.coordinates.push_back(gpsTraces.getRandomCoordinate());
if (benchmark.number_of_results)
{
params.number_of_results = *benchmark.number_of_results;
}
TIMER_START(nearest);
const auto rc = osrm.Nearest(params, result);
TIMER_STOP(nearest);
statistics.push(TIMER_MSEC(nearest));
auto &json_result = std::get<json::Object>(result);
if (rc != Status::Ok ||
json_result.values.find("waypoints") == json_result.values.end())
{
auto code = std::get<json::String>(json_result.values["code"]).value;
if (code != "NoSegment")
{
throw std::runtime_error{"Couldn't find nearest point"};
}
}
}
std::cout << benchmark.name << std::endl;
std::cout << statistics << std::endl;
};
std::vector<Benchmark> benchmarks = {{"10000 nearest, number_of_results=1", 1},
{"10000 nearest, number_of_results=5", 5},
{"10000 nearest, number_of_results=10", 10}};
for (const auto &benchmark : benchmarks)
{
run_benchmark(benchmark);
}
}
void runTripBenchmark(const OSRM &osrm, const GPSTraces &gpsTraces)
{
struct Benchmark
{
std::string name;
size_t coordinates;
};
auto run_benchmark = [&](const Benchmark &benchmark)
{
Statistics statistics;
auto NUM = 1000;
for (int i = 0; i < NUM; ++i)
{
engine::api::ResultT result = json::Object();
TripParameters params;
params.roundtrip = true;
for (size_t i = 0; i < benchmark.coordinates; ++i)
{
params.coordinates.push_back(gpsTraces.getRandomCoordinate());
}
TIMER_START(trip);
const auto rc = osrm.Trip(params, result);
TIMER_STOP(trip);
statistics.push(TIMER_MSEC(trip));
auto &json_result = std::get<json::Object>(result);
if (rc != Status::Ok || json_result.values.find("trips") == json_result.values.end())
{
auto code = std::get<json::String>(json_result.values["code"]).value;
if (code != "NoSegment")
{
throw std::runtime_error{"Couldn't find trip"};
}
}
}
std::cout << benchmark.name << std::endl;
std::cout << statistics << std::endl;
};
std::vector<Benchmark> benchmarks = {
{"1000 trips, 3 coordinates", 3},
{"1000 trips, 4 coordinates", 4},
{"1000 trips, 5 coordinates", 5},
};
for (const auto &benchmark : benchmarks)
{
run_benchmark(benchmark);
}
}
void runTableBenchmark(const OSRM &osrm, const GPSTraces &gpsTraces)
{
struct Benchmark
{
std::string name;
size_t coordinates;
};
auto run_benchmark = [&](const Benchmark &benchmark)
{
Statistics statistics;
auto NUM = 250;
for (int i = 0; i < NUM; ++i)
{
engine::api::ResultT result = json::Object();
TableParameters params;
for (size_t i = 0; i < benchmark.coordinates; ++i)
{
params.coordinates.push_back(gpsTraces.getRandomCoordinate());
}
TIMER_START(table);
const auto rc = osrm.Table(params, result);
TIMER_STOP(table);
statistics.push(TIMER_MSEC(table));
auto &json_result = std::get<json::Object>(result);
if (rc != Status::Ok ||
json_result.values.find("durations") == json_result.values.end())
{
auto code = std::get<json::String>(json_result.values["code"]).value;
if (code != "NoSegment")
{
throw std::runtime_error{"Couldn't compute table"};
}
}
}
std::cout << benchmark.name << std::endl;
std::cout << statistics << std::endl;
};
std::vector<Benchmark> benchmarks = {{"250 tables, 3 coordinates", 3},
{"250 tables, 25 coordinates", 25},
{"250 tables, 50 coordinates", 50},
{"250 tables, 100 coordinates", 100}};
for (const auto &benchmark : benchmarks)
{
run_benchmark(benchmark);
}
}
} // namespace
int main(int argc, const char *argv[])
try
{
if (argc < 5)
{
std::cerr
<< "Usage: " << argv[0]
<< " data.osrm <mld|ch> <path to GPS traces.csv> <route|match|trip|table|nearest>\n";
return EXIT_FAILURE;
}
// Configure based on a .osrm base path, and no datasets in shared mem from osrm-datastore
EngineConfig config;
config.storage_config = {argv[1]};
config.algorithm =
std::string{argv[2]} == "mld" ? EngineConfig::Algorithm::MLD : EngineConfig::Algorithm::CH;
config.use_shared_memory = false;
// Routing machine with several services (such as Route, Table, Nearest, Trip, Match)
OSRM osrm{config};
GPSTraces gpsTraces{42};
gpsTraces.readCSV(argv[3]);
const auto benchmarkToRun = std::string{argv[4]};
if (benchmarkToRun == "route")
{
runRouteBenchmark(osrm, gpsTraces);
}
else if (benchmarkToRun == "match")
{
runMatchBenchmark(osrm, gpsTraces);
}
else if (benchmarkToRun == "nearest")
{
runNearestBenchmark(osrm, gpsTraces);
}
else if (benchmarkToRun == "trip")
{
runTripBenchmark(osrm, gpsTraces);
}
else if (benchmarkToRun == "table")
{
runTableBenchmark(osrm, gpsTraces);
}
else
{
std::cerr << "Unknown benchmark: " << benchmarkToRun << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
catch (const std::exception &e)
{
std::cerr << "Error: " << e.what() << std::endl;
return EXIT_FAILURE;
}

View File

@ -44,21 +44,22 @@ util::json::Array lanesFromIntersection(const guidance::IntermediateIntersection
{
BOOST_ASSERT(intersection.lanes.lanes_in_turn >= 1);
util::json::Array result;
result.values.reserve(intersection.lane_description.size());
LaneID lane_id = intersection.lane_description.size();
for (const auto &lane_desc : intersection.lane_description)
{
--lane_id;
util::json::Object lane;
lane.values["indications"] = toJSON(lane_desc);
lane.values.emplace("indications", toJSON(lane_desc));
if (lane_id >= intersection.lanes.first_lane_from_the_right &&
lane_id <
intersection.lanes.first_lane_from_the_right + intersection.lanes.lanes_in_turn)
lane.values["valid"] = util::json::True();
lane.values.emplace("valid", util::json::True());
else
lane.values["valid"] = util::json::False();
lane.values.emplace("valid", util::json::False());
result.values.push_back(lane);
result.values.emplace_back(std::move(lane));
}
return result;
@ -77,6 +78,7 @@ std::string waypointTypeToString(const guidance::WaypointType waypoint_type)
util::json::Value coordinateToLonLat(const util::Coordinate &coordinate)
{
util::json::Array array;
array.values.reserve(2);
array.values.push_back(static_cast<double>(util::toFloating(coordinate.lon)));
array.values.push_back(static_cast<double>(util::toFloating(coordinate.lat)));
return util::json::Value{std::move(array)};
@ -98,17 +100,20 @@ util::json::Object makeStepManeuver(const guidance::StepManeuver &maneuver)
// These invalid responses should never happen: log if they do happen
BOOST_ASSERT_MSG(maneuver_type != "invalid", "unexpected invalid maneuver type");
step_maneuver.values["type"] = std::move(maneuver_type);
step_maneuver.values.emplace("type", std::move(maneuver_type));
if (detail::isValidModifier(maneuver))
step_maneuver.values["modifier"] =
osrm::guidance::instructionModifierToString(maneuver.instruction.direction_modifier);
step_maneuver.values.emplace(
"modifier",
osrm::guidance::instructionModifierToString(maneuver.instruction.direction_modifier));
step_maneuver.values["location"] = detail::coordinateToLonLat(maneuver.location);
step_maneuver.values["bearing_before"] = detail::roundAndClampBearing(maneuver.bearing_before);
step_maneuver.values["bearing_after"] = detail::roundAndClampBearing(maneuver.bearing_after);
step_maneuver.values.emplace("location", detail::coordinateToLonLat(maneuver.location));
step_maneuver.values.emplace("bearing_before",
detail::roundAndClampBearing(maneuver.bearing_before));
step_maneuver.values.emplace("bearing_after",
detail::roundAndClampBearing(maneuver.bearing_after));
if (maneuver.exit != 0)
step_maneuver.values["exit"] = maneuver.exit;
step_maneuver.values.emplace("exit", maneuver.exit);
return step_maneuver;
}
@ -137,16 +142,16 @@ util::json::Object makeIntersection(const guidance::IntermediateIntersection &in
return util::json::False();
});
result.values["location"] = detail::coordinateToLonLat(intersection.location);
result.values["bearings"] = bearings;
result.values["entry"] = entry;
result.values.emplace("location", detail::coordinateToLonLat(intersection.location));
result.values.emplace("bearings", bearings);
result.values.emplace("entry", entry);
if (intersection.in != guidance::IntermediateIntersection::NO_INDEX)
result.values["in"] = intersection.in;
result.values.emplace("in", intersection.in);
if (intersection.out != guidance::IntermediateIntersection::NO_INDEX)
result.values["out"] = intersection.out;
result.values.emplace("out", intersection.out);
if (detail::hasValidLanes(intersection))
result.values["lanes"] = detail::lanesFromIntersection(intersection);
result.values.emplace("lanes", detail::lanesFromIntersection(intersection));
if (!intersection.classes.empty())
{
@ -157,7 +162,7 @@ util::json::Object makeIntersection(const guidance::IntermediateIntersection &in
std::back_inserter(classes.values),
[](const std::string &class_name)
{ return util::json::String{class_name}; });
result.values["classes"] = std::move(classes);
result.values.emplace("classes", std::move(classes));
}
return result;
@ -166,39 +171,44 @@ util::json::Object makeIntersection(const guidance::IntermediateIntersection &in
util::json::Object makeRouteStep(guidance::RouteStep step, util::json::Value geometry)
{
util::json::Object route_step;
route_step.values["distance"] = std::round(step.distance * 10) / 10.;
route_step.values["duration"] = step.duration;
route_step.values["weight"] = step.weight;
route_step.values["name"] = std::move(step.name);
route_step.values.reserve(15);
route_step.values.emplace("distance", std::round(step.distance * 10) / 10.);
route_step.values.emplace("duration", step.duration);
route_step.values.emplace("weight", step.weight);
route_step.values.emplace("name", step.name);
if (!step.ref.empty())
route_step.values["ref"] = std::move(step.ref);
route_step.values.emplace("ref", step.ref);
if (!step.pronunciation.empty())
route_step.values["pronunciation"] = std::move(step.pronunciation);
route_step.values.emplace("pronunciation", step.pronunciation);
if (!step.destinations.empty())
route_step.values["destinations"] = std::move(step.destinations);
route_step.values.emplace("destinations", step.destinations);
if (!step.exits.empty())
route_step.values["exits"] = std::move(step.exits);
route_step.values.emplace("exits", step.exits);
if (!step.rotary_name.empty())
{
route_step.values["rotary_name"] = std::move(step.rotary_name);
route_step.values.emplace("rotary_name", step.rotary_name);
if (!step.rotary_pronunciation.empty())
{
route_step.values["rotary_pronunciation"] = std::move(step.rotary_pronunciation);
route_step.values.emplace("rotary_pronunciation", step.rotary_pronunciation);
}
}
route_step.values["mode"] = extractor::travelModeToString(step.mode);
route_step.values["maneuver"] = makeStepManeuver(step.maneuver);
route_step.values["geometry"] = std::move(geometry);
route_step.values["driving_side"] = step.is_left_hand_driving ? "left" : "right";
route_step.values.emplace("mode", extractor::travelModeToString(step.mode));
route_step.values.emplace("maneuver", makeStepManeuver(step.maneuver));
route_step.values.emplace("geometry", std::move(geometry));
route_step.values.emplace("driving_side", step.is_left_hand_driving ? "left" : "right");
util::json::Array intersections;
intersections.values.reserve(step.intersections.size());
std::transform(step.intersections.begin(),
step.intersections.end(),
std::back_inserter(intersections.values),
makeIntersection);
route_step.values["intersections"] = std::move(intersections);
route_step.values.emplace("intersections", std::move(intersections));
return route_step;
}
@ -209,14 +219,16 @@ util::json::Object makeRoute(const guidance::Route &route,
const char *weight_name)
{
util::json::Object json_route;
json_route.values["distance"] = route.distance;
json_route.values["duration"] = route.duration;
json_route.values["weight"] = route.weight;
json_route.values["weight_name"] = weight_name;
json_route.values["legs"] = std::move(legs);
json_route.values.reserve(6);
json_route.values.emplace("distance", route.distance);
json_route.values.emplace("duration", route.duration);
json_route.values.emplace("weight", route.weight);
json_route.values.emplace("weight_name", weight_name);
json_route.values.emplace("legs", std::move(legs));
if (geometry)
{
json_route.values["geometry"] = *std::move(geometry);
json_route.values.emplace("geometry", *std::move(geometry));
}
return json_route;
}
@ -225,9 +237,11 @@ util::json::Object
makeWaypoint(const util::Coordinate &location, const double &distance, std::string name)
{
util::json::Object waypoint;
waypoint.values["location"] = detail::coordinateToLonLat(location);
waypoint.values["name"] = std::move(name);
waypoint.values["distance"] = distance;
waypoint.values.reserve(3);
waypoint.values.emplace("location", detail::coordinateToLonLat(location));
waypoint.values.emplace("name", std::move(name));
waypoint.values.emplace("distance", distance);
return waypoint;
}
@ -237,26 +251,29 @@ util::json::Object makeWaypoint(const util::Coordinate &location,
const Hint &location_hints)
{
auto waypoint = makeWaypoint(location, distance, std::move(name));
waypoint.values["hint"] = location_hints.ToBase64();
waypoint.values.reserve(1);
waypoint.values.emplace("hint", location_hints.ToBase64());
return waypoint;
}
util::json::Object makeRouteLeg(guidance::RouteLeg leg, util::json::Array steps)
{
util::json::Object route_leg;
route_leg.values["distance"] = leg.distance;
route_leg.values["duration"] = leg.duration;
route_leg.values["weight"] = leg.weight;
route_leg.values["summary"] = std::move(leg.summary);
route_leg.values["steps"] = std::move(steps);
route_leg.values.reserve(5);
route_leg.values.emplace("distance", leg.distance);
route_leg.values.emplace("duration", leg.duration);
route_leg.values.emplace("weight", leg.weight);
route_leg.values.emplace("summary", std::move(leg.summary));
route_leg.values.emplace("steps", std::move(steps));
return route_leg;
}
util::json::Object
makeRouteLeg(guidance::RouteLeg leg, util::json::Array steps, util::json::Object annotation)
{
util::json::Object route_leg = makeRouteLeg(std::move(leg), std::move(steps));
route_leg.values["annotation"] = std::move(annotation);
route_leg.values.reserve(1);
route_leg.values.emplace("annotation", std::move(annotation));
return route_leg;
}

Binary file not shown.