Repo created
This commit is contained in:
parent
4af19165ec
commit
68073add76
12458 changed files with 12350765 additions and 2 deletions
145
libs/routing/routing_quality/api/google/google_api.cpp
Normal file
145
libs/routing/routing_quality/api/google/google_api.cpp
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
#include "routing/routing_quality/api/google/google_api.hpp"
|
||||
|
||||
#include "platform/http_client.hpp"
|
||||
|
||||
#include "coding/serdes_json.hpp"
|
||||
|
||||
#include "geometry/mercator.hpp"
|
||||
|
||||
#include "base/assert.hpp"
|
||||
#include "base/logging.hpp"
|
||||
|
||||
#include <chrono>
|
||||
#include <ctime>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
|
||||
namespace
|
||||
{
|
||||
auto GetNextDayAtNight(int32_t startTimeZoneUTC)
|
||||
{
|
||||
auto now = std::chrono::system_clock::now();
|
||||
|
||||
std::time_t nowTimeT = std::chrono::system_clock::to_time_t(now);
|
||||
std::tm * date = std::localtime(&nowTimeT);
|
||||
|
||||
std::time_t constexpr kSecondsInDay = 24 * 60 * 60;
|
||||
std::time_t nextDay = std::mktime(date) + kSecondsInDay;
|
||||
|
||||
std::tm * nextDayDate = std::localtime(&nextDay);
|
||||
|
||||
long constexpr kSecondsInHour = 3600;
|
||||
int const curUTCOffset = static_cast<int>(nextDayDate->tm_gmtoff / kSecondsInHour);
|
||||
|
||||
nextDayDate->tm_sec = 0;
|
||||
nextDayDate->tm_min = 0;
|
||||
|
||||
int constexpr kStartHour = 22;
|
||||
// If in Moscow (UTC+3) it is 20:00, in New York (UTC-5):
|
||||
// 20:00 - 03:00 (Moscow) = 19:00 (UTC+0), so in New York: 19:00 - 05:00 = 14:00 (UTC-5).
|
||||
// Thus if we want to find such time (Y hours) in Moscow (UTC+3) so that in New York (UTC-5)
|
||||
// it's must be X hours, we use such formula:
|
||||
// 1) Y (UTC+3) - 03:00 = UTC+0
|
||||
// 2) Y (UTC+3) - 03:00 + 05:00 = X (UTC+5)
|
||||
// 2 => Y = X + 03:00 - 05:00
|
||||
// For google api we want to find such Y, that it's will be |kStartHour| hours in any place.
|
||||
nextDayDate->tm_hour = kStartHour + curUTCOffset - startTimeZoneUTC;
|
||||
|
||||
return std::chrono::system_clock::from_time_t(std::mktime(nextDayDate));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace routing_quality
|
||||
{
|
||||
namespace api
|
||||
{
|
||||
namespace google
|
||||
{
|
||||
// static
|
||||
std::string const GoogleApi::kApiName = "google";
|
||||
|
||||
GoogleApi::GoogleApi(std::string const & token) : RoutingApi(kApiName, token, kMaxRPS) {}
|
||||
|
||||
Response GoogleApi::CalculateRoute(Params const & params, int32_t startTimeZoneUTC) const
|
||||
{
|
||||
Response response;
|
||||
GoogleResponse googleResponse = MakeRequest(params, startTimeZoneUTC);
|
||||
|
||||
response.m_params = params;
|
||||
response.m_code = googleResponse.m_code;
|
||||
for (auto const & route : googleResponse.m_routes)
|
||||
{
|
||||
CHECK_EQUAL(route.m_legs.size(), 1, ("No waypoints support for google api."));
|
||||
auto const & leg = route.m_legs.back();
|
||||
|
||||
api::Route apiRoute;
|
||||
apiRoute.m_eta = leg.m_duration.m_seconds;
|
||||
apiRoute.m_distance = leg.m_distance.m_meters;
|
||||
|
||||
auto const startLatLon = leg.m_steps.front().m_startLocation;
|
||||
apiRoute.m_waypoints.emplace_back(startLatLon.m_lat, startLatLon.m_lon);
|
||||
for (auto const & step : leg.m_steps)
|
||||
{
|
||||
auto const & prev = step.m_startLocation;
|
||||
auto const & next = step.m_endLocation;
|
||||
|
||||
auto const & prevWaypoint = apiRoute.m_waypoints.back();
|
||||
CHECK(prevWaypoint.m_lat == prev.m_lat && prevWaypoint.m_lon == prev.m_lon, ());
|
||||
|
||||
apiRoute.m_waypoints.emplace_back(next.m_lat, next.m_lon);
|
||||
}
|
||||
|
||||
response.m_routes.emplace_back(std::move(apiRoute));
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
GoogleResponse GoogleApi::MakeRequest(Params const & params, int32_t startTimeZoneUTC) const
|
||||
{
|
||||
GoogleResponse googleResponse;
|
||||
platform::HttpClient request(GetDirectionsURL(params, startTimeZoneUTC));
|
||||
|
||||
if (request.RunHttpRequest() && !request.WasRedirected() && request.ErrorCode() == 200)
|
||||
{
|
||||
auto const & response = request.ServerResponse();
|
||||
CHECK(!response.empty(), ());
|
||||
{
|
||||
googleResponse.m_code = ResultCode::ResponseOK;
|
||||
coding::DeserializerJson des(response);
|
||||
des(googleResponse);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LWARNING, (request.ErrorCode(), request.ServerResponse()));
|
||||
googleResponse.m_code = ResultCode::Error;
|
||||
}
|
||||
|
||||
return googleResponse;
|
||||
}
|
||||
|
||||
std::string GoogleApi::GetDirectionsURL(Params const & params, int32_t startTimeZoneUTC) const
|
||||
{
|
||||
CHECK(-12 <= startTimeZoneUTC && startTimeZoneUTC <= 12, ("Invalid UTC zone."));
|
||||
|
||||
static std::string const kBaseUrl = "https://maps.googleapis.com/maps/api/directions/json?";
|
||||
|
||||
auto const start = mercator::ToLatLon(params.m_waypoints.GetPointFrom());
|
||||
auto const finish = mercator::ToLatLon(params.m_waypoints.GetPointTo());
|
||||
|
||||
auto const nextDayAtNight = GetNextDayAtNight(startTimeZoneUTC);
|
||||
auto const secondFromEpoch = nextDayAtNight.time_since_epoch().count() / 1000000;
|
||||
LOG(LDEBUG, ("&departure_time =", secondFromEpoch));
|
||||
|
||||
std::stringstream ss;
|
||||
ss << kBaseUrl << "&origin=" << std::to_string(start.m_lat) << "," << std::to_string(start.m_lon)
|
||||
<< "&destination=" << std::to_string(finish.m_lat) << "," << std::to_string(finish.m_lon)
|
||||
<< "&key=" << GetAccessToken() << "&alternatives=true"
|
||||
<< "&departure_time=" << secondFromEpoch;
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
} // namespace google
|
||||
} // namespace api
|
||||
} // namespace routing_quality
|
||||
37
libs/routing/routing_quality/api/google/google_api.hpp
Normal file
37
libs/routing/routing_quality/api/google/google_api.hpp
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
#pragma once
|
||||
|
||||
#include "routing/routing_quality/api/api.hpp"
|
||||
|
||||
#include "routing/routing_quality/api/google/types.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace routing_quality
|
||||
{
|
||||
namespace api
|
||||
{
|
||||
namespace google
|
||||
{
|
||||
class GoogleApi : public RoutingApi
|
||||
{
|
||||
public:
|
||||
explicit GoogleApi(std::string const & token);
|
||||
|
||||
// According to:
|
||||
// https://developers.google.com/maps/faq#usage_apis
|
||||
static uint32_t constexpr kMaxRPS = 50;
|
||||
static std::string const kApiName;
|
||||
|
||||
// RoutingApi overrides:
|
||||
// @{
|
||||
Response CalculateRoute(Params const & params, int32_t startTimeZoneUTC) const override;
|
||||
// @}
|
||||
|
||||
private:
|
||||
GoogleResponse MakeRequest(Params const & params, int32_t startTimeZoneUTC) const;
|
||||
std::string GetDirectionsURL(Params const & params, int32_t startTimeZoneUTC) const;
|
||||
};
|
||||
} // namespace google
|
||||
} // namespace api
|
||||
} // namespace routing_quality
|
||||
32
libs/routing/routing_quality/api/google/types.cpp
Normal file
32
libs/routing/routing_quality/api/google/types.cpp
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#include "routing/routing_quality/api/google/types.hpp"
|
||||
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <tuple>
|
||||
|
||||
namespace routing_quality
|
||||
{
|
||||
namespace api
|
||||
{
|
||||
namespace google
|
||||
{
|
||||
bool LatLon::operator==(LatLon const & rhs) const
|
||||
{
|
||||
return std::tie(m_lat, m_lon) == std::tie(rhs.m_lat, rhs.m_lon);
|
||||
}
|
||||
|
||||
bool Step::operator==(Step const & rhs) const
|
||||
{
|
||||
return std::tie(m_startLocation, m_endLocation) == std::tie(rhs.m_startLocation, rhs.m_endLocation);
|
||||
}
|
||||
|
||||
std::string DebugPrint(LatLon const & latlon)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << std::setprecision(20);
|
||||
ss << "google::LatLon(" << latlon.m_lat << ", " << latlon.m_lon << ")";
|
||||
return ss.str();
|
||||
}
|
||||
} // namespace google
|
||||
} // namespace api
|
||||
} // namespace routing_quality
|
||||
77
libs/routing/routing_quality/api/google/types.hpp
Normal file
77
libs/routing/routing_quality/api/google/types.hpp
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
#pragma once
|
||||
|
||||
#include "routing/routing_quality/api/api.hpp"
|
||||
|
||||
#include "base/visitor.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace routing_quality
|
||||
{
|
||||
namespace api
|
||||
{
|
||||
namespace google
|
||||
{
|
||||
struct LatLon
|
||||
{
|
||||
DECLARE_VISITOR(visitor(m_lat, "lat"), visitor(m_lon, "lng"))
|
||||
|
||||
bool operator==(LatLon const & rhs) const;
|
||||
|
||||
double m_lat = 0.0;
|
||||
double m_lon = 0.0;
|
||||
};
|
||||
|
||||
struct Step
|
||||
{
|
||||
DECLARE_VISITOR(visitor(m_startLocation, "start_location"), visitor(m_endLocation, "end_location"))
|
||||
|
||||
bool operator==(Step const & rhs) const;
|
||||
|
||||
LatLon m_startLocation;
|
||||
LatLon m_endLocation;
|
||||
};
|
||||
|
||||
struct Duration
|
||||
{
|
||||
DECLARE_VISITOR(visitor(m_seconds, "value"))
|
||||
|
||||
double m_seconds = 0.0;
|
||||
};
|
||||
|
||||
struct Distance
|
||||
{
|
||||
DECLARE_VISITOR(visitor(m_meters, "value"))
|
||||
|
||||
double m_meters = 0.0;
|
||||
};
|
||||
|
||||
struct Leg
|
||||
{
|
||||
DECLARE_VISITOR(visitor(m_distance, "distance"), visitor(m_duration, "duration"), visitor(m_steps, "steps"))
|
||||
|
||||
Distance m_distance;
|
||||
Duration m_duration;
|
||||
std::vector<Step> m_steps;
|
||||
};
|
||||
|
||||
struct Route
|
||||
{
|
||||
DECLARE_VISITOR(visitor(m_legs, "legs"))
|
||||
|
||||
std::vector<Leg> m_legs;
|
||||
};
|
||||
|
||||
struct GoogleResponse
|
||||
{
|
||||
DECLARE_VISITOR(visitor(m_routes, "routes"))
|
||||
|
||||
ResultCode m_code = ResultCode::Error;
|
||||
std::vector<Route> m_routes;
|
||||
};
|
||||
|
||||
std::string DebugPrint(LatLon const & latlon);
|
||||
} // namespace google
|
||||
} // namespace api
|
||||
} // namespace routing_quality
|
||||
Loading…
Add table
Add a link
Reference in a new issue