diff --git a/generator/CMakeLists.txt b/generator/CMakeLists.txt index 15a7198030..1e1818f295 100644 --- a/generator/CMakeLists.txt +++ b/generator/CMakeLists.txt @@ -227,6 +227,8 @@ set( traffic_generator.hpp transit_generator.cpp transit_generator.hpp + transit_generator_experimental.cpp + transit_generator_experimental.hpp translator.cpp translator.hpp translator_coastline.cpp diff --git a/generator/generator_tool/generator_tool.cpp b/generator/generator_tool/generator_tool.cpp index 0cf0a5ed19..2b625455c6 100644 --- a/generator/generator_tool/generator_tool.cpp +++ b/generator/generator_tool/generator_tool.cpp @@ -30,6 +30,7 @@ #include "generator/statistics.hpp" #include "generator/traffic_generator.hpp" #include "generator/transit_generator.hpp" +#include "generator/transit_generator_experimental.hpp" #include "generator/translator_collection.hpp" #include "generator/translator_factory.hpp" #include "generator/ugc_section_builder.hpp" @@ -461,8 +462,8 @@ MAIN_WITH_ERROR_HANDLING([](int argc, char ** argv) if (!FLAGS_transit_path_experimental.empty()) { - // TODO(o.khlopkova) Build transit. - LOG(LINFO, ("Transit experimental building.")); + transit::experimental::BuildTransit(path, country, osmToFeatureFilename, + FLAGS_transit_path_experimental); } else if (!FLAGS_transit_path.empty()) { diff --git a/generator/transit_generator_experimental.cpp b/generator/transit_generator_experimental.cpp new file mode 100644 index 0000000000..922203cadd --- /dev/null +++ b/generator/transit_generator_experimental.cpp @@ -0,0 +1,106 @@ +#include "generator/transit_generator_experimental.hpp" + +#include "generator/utils.hpp" + +#include "routing/index_router.hpp" +#include "routing/road_graph.hpp" +#include "routing/routing_exceptions.hpp" +#include "routing/vehicle_mask.hpp" + +#include "storage/country_info_getter.hpp" +#include "storage/routing_helpers.hpp" + +#include "transit/experimental/transit_types_experimental.hpp" + +#include "indexer/mwm_set.hpp" + +#include "platform/country_file.hpp" +#include "platform/platform.hpp" + +#include "coding/file_writer.hpp" + +#include "geometry/point2d.hpp" +#include "geometry/rect2d.hpp" +#include "geometry/region2d.hpp" + +#include "base/assert.hpp" +#include "base/exception.hpp" +#include "base/file_name_utils.hpp" +#include "base/logging.hpp" + +#include "defines.hpp" + +#include +#include + +#include "3party/jansson/src/jansson.h" + +using namespace generator; +using namespace platform; +using namespace routing; +using namespace routing::transit; +using namespace std; +using namespace storage; + +namespace transit +{ +namespace experimental +{ +void FillOsmIdToFeatureIdsMap(string const & osmIdToFeatureIdsPath, OsmIdToFeatureIdsMap & mapping) +{ + bool const mappedIds = ForEachOsmId2FeatureId( + osmIdToFeatureIdsPath, [&mapping](auto const & compositeId, auto featureId) { + mapping[compositeId.m_mainId].push_back(featureId); + }); + CHECK(mappedIds, (osmIdToFeatureIdsPath)); +} + +string GetMwmPath(string const & mwmDir, CountryId const & countryId) +{ + return base::JoinPath(mwmDir, countryId + DATA_FILE_EXTENSION); +} + +/// \brief Calculates best pedestrian segment for every gate in |graphData.m_gates|. +/// The result of the calculation is set to |Gate::m_bestPedestrianSegment| of every gate +/// from |graphData.m_gates|. +/// \note All gates in |graphData.m_gates| must have a valid |m_point| field before the call. +void CalculateBestPedestrianSegments(string const & mwmPath, CountryId const & countryId, + TransitData & graphData) +{ + // TODO(o.khlopkova) Find best segments for gates and not-subway stops. +} + +void DeserializeFromJson(OsmIdToFeatureIdsMap const & mapping, std::string const & transitJsonsPath, + TransitData & data) +{ + data.DeserializeFromJson(transitJsonsPath, mapping); +} + +void ProcessData(string const & mwmPath, CountryId const & countryId, + OsmIdToFeatureIdsMap const & osmIdToFeatureIdsMap, TransitData & data) +{ + CalculateBestPedestrianSegments(mwmPath, countryId, data); + data.Sort(); + data.CheckValidSortedUnique(); +} + +void BuildTransit(string const & mwmDir, CountryId const & countryId, + string const & osmIdToFeatureIdsPath, string const & transitDir) +{ + LOG(LINFO, ("Building experimental transit section for", countryId, "mwmDir:", mwmDir)); + string const mwmPath = GetMwmPath(mwmDir, countryId); + OsmIdToFeatureIdsMap mapping; + FillOsmIdToFeatureIdsMap(osmIdToFeatureIdsPath, mapping); + + TransitData data; + DeserializeFromJson(mapping, base::JoinPath(transitDir, countryId), data); + + // Transit section can be empty. + if (data.IsEmpty()) + return; + + // TODO(o.khlopkova) Implement filling best pedestrian segments for gates and stops, check + // if result data is not valid and serialize it to mwm transit section. +} +} // namespace experimental +} // namespace transit diff --git a/generator/transit_generator_experimental.hpp b/generator/transit_generator_experimental.hpp new file mode 100644 index 0000000000..51b7f1bbbe --- /dev/null +++ b/generator/transit_generator_experimental.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include "storage/storage_defines.hpp" + +#include "transit/experimental/transit_data.hpp" + +#include + +namespace transit +{ +namespace experimental +{ +/// \brief Fills |data| according to transit files (|transitJsonPath|). +/// \note Stops and gates items may contain osm_id field. If it is present and the mapping +/// |osmIdToFeatureIdsPath| contains it then its value is used as id. Otherwise generated on the +/// previous step (gtfs_converter) id is used. +void DeserializeFromJson(OsmIdToFeatureIdsMap const & mapping, std::string const & transitJsonsPath, + TransitData & data); + +/// \brief Calculates and adds additional information to transit |data| after deserializing it +/// from json. +void ProcessData(std::string const & mwmPath, storage::CountryId const & countryId, + OsmIdToFeatureIdsMap const & osmIdToFeatureIdsMap, TransitData & data); + +/// \brief Builds transit section in the mwm based on transit data in json which is already clipped +/// by the mwm borders. +/// \param mwmDir is the directory where mwm is located. +/// \param countryId is an mwm name without extension of the processed mwm. +/// \param osmIdToFeatureIdsPath is a path to a file with osm id to feature ids mapping. +/// \param transitDir is directory with transit jsons. +/// It's assumed that files have extension TRANSIT_FILE_EXTENSION. +/// \note An mwm pointed by |mwmPath| should contain: +/// * feature geometry +/// * index graph (ROUTING_FILE_TAG) +void BuildTransit(std::string const & mwmDir, storage::CountryId const & countryId, + std::string const & osmIdToFeatureIdsPath, std::string const & transitDir); +} // namespace experimental +} // namespace transit diff --git a/routing/index_router.cpp b/routing/index_router.cpp index 01e3e6fc0e..72b3c541b2 100644 --- a/routing/index_router.cpp +++ b/routing/index_router.cpp @@ -22,7 +22,7 @@ #include "routing/turns_generator.hpp" #include "routing/vehicle_mask.hpp" -#include "transit/transit_speed_limits.hpp" +#include "transit/transit_entities.hpp" #include "routing_common/bicycle_model.hpp" #include "routing_common/car_model.hpp" @@ -76,7 +76,7 @@ double CalcMaxSpeed(NumMwmIds const & numMwmIds, VehicleType vehicleType) { if (vehicleType == VehicleType::Transit) - return transit::kTransitMaxSpeedKMpH; + return kTransitMaxSpeedKMpH; double maxSpeed = 0.0; numMwmIds.ForEachId([&](NumMwmId id) { diff --git a/transit/CMakeLists.txt b/transit/CMakeLists.txt index c742837bbc..ebef419c16 100644 --- a/transit/CMakeLists.txt +++ b/transit/CMakeLists.txt @@ -6,11 +6,15 @@ include_directories( set( SRC + experimental/transit_data.cpp + experimental/transit_data.hpp + experimental/transit_types_experimental.cpp + experimental/transit_types_experimental.hpp transit_display_info.hpp + transit_entities.hpp transit_graph_data.cpp transit_graph_data.hpp transit_serdes.hpp - transit_speed_limits.hpp transit_types.cpp transit_types.hpp ) diff --git a/transit/experimental/transit_data.cpp b/transit/experimental/transit_data.cpp new file mode 100644 index 0000000000..d00629a555 --- /dev/null +++ b/transit/experimental/transit_data.cpp @@ -0,0 +1,377 @@ +#include "transit/experimental/transit_data.hpp" + +#include "transit/transit_entities.hpp" + +#include "base/assert.hpp" +#include "base/file_name_utils.hpp" +#include "base/logging.hpp" + +#include +#include + +#include "3party/jansson/myjansson.hpp" +#include "3party/opening_hours/opening_hours.hpp" + +namespace transit +{ +namespace experimental +{ +TransitId GetIdFromJson(json_t * obj) +{ + TransitId id; + FromJSONObject(obj, "id", id); + return id; +} + +std::vector GetWeightsFromJson(json_t * obj) +{ + json_t * arr = base::GetJSONObligatoryField(obj, "weights"); + CHECK(json_is_array(arr), ()); + + size_t const count = json_array_size(arr); + std::vector weights; + weights.resize(count); + + for (size_t i = 0; i < count; ++i) + { + json_t * item = json_array_get(arr, i); + + TimeFromGateToStop weight; + FromJSONObject(item, "stop_id", weight.m_stopId); + FromJSONObject(item, "time_to_stop", weight.m_timeSeconds); + weights.emplace_back(weight); + } + + CHECK(!weights.empty(), ()); + return weights; +} + +IdList GetStopIdsFromJson(json_t * obj) +{ + json_t * arr = base::GetJSONObligatoryField(obj, "stops_ids"); + CHECK(json_is_array(arr), ()); + + size_t const count = json_array_size(arr); + IdList stopIds; + stopIds.resize(count); + + for (size_t i = 0; i < count; ++i) + { + json_t * item = json_array_get(arr, i); + TransitId id = 0; + FromJSON(item, id); + stopIds.emplace_back(id); + } + + return stopIds; +} + +std::vector GetIntervalsFromJson(json_t * obj) +{ + json_t * arr = base::GetJSONObligatoryField(obj, "intervals"); + CHECK(json_is_array(arr), ()); + + std::vector intervals; + size_t const count = json_array_size(arr); + intervals.reserve(count); + + for (size_t i = 0; i < count; ++i) + { + json_t * item = json_array_get(arr, i); + CHECK(json_is_object(item), ()); + + LineInterval interval; + FromJSONObject(item, "interval_s", interval.m_headwayS); + + std::string serviceHoursStr; + FromJSONObject(item, "service_hours", serviceHoursStr); + interval.m_timeIntervals = osmoh::OpeningHours(serviceHoursStr); + intervals.emplace_back(interval); + } + + return intervals; +} + +m2::PointD GetPointFromJson(json_t * obj) +{ + CHECK(json_is_object(obj), ()); + + m2::PointD point; + FromJSONObject(obj, "x", point.x); + FromJSONObject(obj, "y", point.y); + return point; +} + +std::vector GetPointsFromJson(json_t * obj) +{ + json_t * arr = base::GetJSONObligatoryField(obj, "points"); + CHECK(json_is_array(arr), ()); + + std::vector points; + size_t const count = json_array_size(arr); + points.reserve(count); + + for (size_t i = 0; i < count; ++i) + { + json_t * item = json_array_get(arr, i); + points.emplace_back(GetPointFromJson(item)); + } + + return points; +} + +TimeTable GetTimeTableFromJson(json_t * obj) +{ + json_t * arr = base::GetJSONObligatoryField(obj, "timetable"); + CHECK(json_is_array(arr), ()); + + TimeTable timetable; + + for (size_t i = 0; i < json_array_size(arr); ++i) + { + json_t * item = json_array_get(arr, i); + CHECK(json_is_object(item), ()); + + TransitId lineId; + std::string arrivalsStr; + FromJSONObject(item, "line_id", lineId); + FromJSONObject(item, "arrivals", arrivalsStr); + + osmoh::OpeningHours arrivals(arrivalsStr); + CHECK(timetable.emplace(lineId, arrivals).second, ()); + } + + return timetable; +} + +Translations GetTranslationsFromJson(json_t * obj, std::string const & field) +{ + json_t * arr = base::GetJSONObligatoryField(obj, field); + CHECK(json_is_array(arr), ()); + Translations translations; + + for (size_t i = 0; i < json_array_size(arr); ++i) + { + json_t * item = json_array_get(arr, i); + CHECK(json_is_object(item), ()); + std::string lang; + std::string text; + FromJSONObject(item, "lang", lang); + FromJSONObject(item, "text", text); + CHECK(translations.emplace(lang, text).second, ()); + } + + return translations; +} + +ShapeLink GetShapeLinkFromJson(json_t * obj) +{ + json_t * shapeLinkObj = base::GetJSONObligatoryField(obj, "shape"); + CHECK(json_is_object(shapeLinkObj), ()); + + ShapeLink shapeLink; + FromJSONObject(shapeLinkObj, "id", shapeLink.m_shapeId); + FromJSONObject(shapeLinkObj, "start_index", shapeLink.m_startIndex); + FromJSONObject(shapeLinkObj, "end_index", shapeLink.m_endIndex); + + return shapeLink; +} + +std::tuple CalculateIds(base::Json const & obj, + OsmIdToFeatureIdsMap const & mapping) +{ + OsmId osmId = kInvalidOsmId; + FeatureId featureId = kInvalidFeatureId; + TransitId id = kInvalidTransitId; + + // Osm id is present in subway items and is absent in all other public transport items. + FromJSONObjectOptionalField(obj.get(), "osm_id", osmId); + if (osmId == 0) + { + id = GetIdFromJson(obj.get()); + osmId = kInvalidOsmId; + } + else + { + featureId = GetIdFromJson(obj.get()); + base::GeoObjectId const geoId(osmId); + auto const it = mapping.find(geoId); + if (it != mapping.cend()) + { + CHECK(!it->second.empty(), ("Osm id", osmId, "encoded as", geoId.GetEncodedId(), + "from transit does not correspond to any feature.")); + if (it->second.size() != 1) + { + // |osmId| corresponds to several feature ids. It may happen in case of stops, + // if a stop is present as a relation. It's a rare case. + LOG(LWARNING, ("Osm id", osmId, "encoded as", geoId.GetEncodedId(), "corresponds to", + it->second.size(), "feature ids.")); + } + featureId = it->second[0]; + } + } + + return {osmId, featureId, id}; +} + +void Read(base::Json const & obj, std::vector & networks) +{ + networks.emplace_back(GetIdFromJson(obj.get()), GetTranslationsFromJson(obj.get(), "title")); +} + +void Read(base::Json const & obj, std::vector & routes) +{ + TransitId const id = GetIdFromJson(obj.get()); + TransitId networkId; + std::string routeType; + std::string color; + Translations title; + + FromJSONObject(obj.get(), "network_id", networkId); + FromJSONObject(obj.get(), "color", color); + FromJSONObject(obj.get(), "type", routeType); + title = GetTranslationsFromJson(obj.get(), "title"); + + routes.emplace_back(id, networkId, routeType, title, color); +} + +void Read(base::Json const & obj, std::vector & lines) +{ + TransitId const id = GetIdFromJson(obj.get()); + TransitId routeId; + FromJSONObject(obj.get(), "route_id", routeId); + ShapeLink const shapeLink = GetShapeLinkFromJson(obj.get()); + Translations const title = GetTranslationsFromJson(obj.get(), "title"); + + // TODO (o.khlopkova) add "number" to gtfs converter pipeline + // and fill number with GetTranslationsFromJson(obj.get(), "number"). + Translations const number; + IdList const stopIds = GetStopIdsFromJson(obj.get()); + + std::vector const intervals = GetIntervalsFromJson(obj.get()); + + std::string serviceDaysStr; + FromJSONObject(obj.get(), "service_days", serviceDaysStr); + osmoh::OpeningHours const serviceDays(serviceDaysStr); + + lines.emplace_back(id, routeId, shapeLink, title, number, stopIds, intervals, serviceDays); +} + +void Read(base::Json const & obj, std::vector & stops, OsmIdToFeatureIdsMap const & mapping) +{ + auto const & [osmId, featureId, id] = CalculateIds(obj, mapping); + + Translations const title = GetTranslationsFromJson(obj.get(), "title"); + TimeTable const timetable = GetTimeTableFromJson(obj.get()); + m2::PointD const point = GetPointFromJson(base::GetJSONObligatoryField(obj.get(), "point")); + + stops.emplace_back(id, featureId, osmId, title, timetable, point); +} + +void Read(base::Json const & obj, std::vector & shapes) +{ + TransitId const id = GetIdFromJson(obj.get()); + std::vector const polyline = GetPointsFromJson(obj.get()); + shapes.emplace_back(id, polyline); +} + +void Read(base::Json const & obj, std::vector & edges) +{ + TransitId stopFrom = kInvalidTransitId; + TransitId stopTo = kInvalidTransitId; + + FromJSONObject(obj.get(), "stop_id_from", stopFrom); + FromJSONObject(obj.get(), "stop_id_to", stopTo); + EdgeWeight weight; + FromJSONObject(obj.get(), "weight", weight); + + TransitId lineId = 0; + ShapeLink shapeLink; + bool isTransfer = false; + + FromJSONObjectOptionalField(obj.get(), "line_id", lineId); + if (lineId == 0) + { + lineId = kInvalidTransitId; + isTransfer = true; + } + else + { + shapeLink = GetShapeLinkFromJson(obj.get()); + } + + edges.emplace_back(stopFrom, stopTo, weight, lineId, isTransfer, shapeLink); +} + +void Read(base::Json const & obj, std::vector & transfers) +{ + TransitId const id = GetIdFromJson(obj.get()); + m2::PointD const point = GetPointFromJson(base::GetJSONObligatoryField(obj.get(), "point")); + IdList const stopIds = GetStopIdsFromJson(obj.get()); + transfers.emplace_back(id, point, stopIds); +} + +void Read(base::Json const & obj, std::vector & gates, OsmIdToFeatureIdsMap const & mapping) +{ + // TODO(o.khlopkova) Inject subways to public transport jsons. + auto const & [osmId, featureId, id] = CalculateIds(obj, mapping); + + std::vector const weights = GetWeightsFromJson(obj.get()); + + bool isEntrance = false; + bool isExit = false; + FromJSONObject(obj.get(), "entrance", isEntrance); + FromJSONObject(obj.get(), "exit", isExit); + + m2::PointD const point = GetPointFromJson(base::GetJSONObligatoryField(obj.get(), "point")); + + gates.emplace_back(id, featureId, osmId, isEntrance, isExit, weights, point); +} + +template +void ReadData(std::string const & path, Args &&... args) +{ + std::ifstream input; + input.exceptions(std::ifstream::badbit); + + try + { + input.open(path); + CHECK(input.is_open(), (path)); + std::string line; + + while (std::getline(input, line)) + { + if (line.empty()) + continue; + + base::Json jsonObject(line); + CHECK(jsonObject.get() != nullptr, ("Error parsing json from line:", line)); + Read(jsonObject, std::forward(args)...); + } + } + catch (std::ifstream::failure const & se) + { + LOG(LERROR, ("Exception reading line-by-line json from file", path, se.what())); + } + catch (base::Json::Exception const & je) + { + LOG(LERROR, ("Exception parsing json", path, je.what())); + } +} + +void TransitData::DeserializeFromJson(std::string const & dirWithJsons, + OsmIdToFeatureIdsMap const & mapping) +{ + ReadData(base::JoinPath(dirWithJsons, kNetworksFile), m_networks); + ReadData(base::JoinPath(dirWithJsons, kRoutesFile), m_routes); + ReadData(base::JoinPath(dirWithJsons, kLinesFile), m_lines); + ReadData(base::JoinPath(dirWithJsons, kStopsFile), m_stops, mapping); + ReadData(base::JoinPath(dirWithJsons, kShapesFile), m_shapes); + ReadData(base::JoinPath(dirWithJsons, kEdgesFile), m_edges); + ReadData(base::JoinPath(dirWithJsons, kEdgesTransferFile), m_edges); + ReadData(base::JoinPath(dirWithJsons, kTransfersFile), m_transfers); + ReadData(base::JoinPath(dirWithJsons, kGatesFile), m_gates, mapping); +} +} // namespace experimental +} // namespace transit diff --git a/transit/experimental/transit_data.hpp b/transit/experimental/transit_data.hpp new file mode 100644 index 0000000000..94af4ee12e --- /dev/null +++ b/transit/experimental/transit_data.hpp @@ -0,0 +1,93 @@ +#pragma once + +#include "transit/experimental/transit_types_experimental.hpp" + +#include "coding/reader.hpp" +#include "coding/writer.hpp" + +#include "geometry/point2d.hpp" +#include "geometry/region2d.hpp" + +#include "base/exception.hpp" +#include "base/geo_object_id.hpp" +#include "base/visitor.hpp" + +#include +#include +#include +#include +#include +#include + +namespace transit +{ +namespace experimental +{ +using OsmIdToFeatureIdsMap = std::map>; + +/// \brief The class contains all the information to make TRANSIT_FILE_TAG section. +class TransitData +{ +public: + void DeserializeFromJson(std::string const & dirWithJsons, OsmIdToFeatureIdsMap const & mapping); + /// \note This method changes only |m_header| and fills it with correct offsets. + // TODO(o.khlopkova) Add implementation for methods: + void Serialize(Writer & writer) {} + void DeserializeAll(Reader & reader) {} + void DeserializeForRouting(Reader & reader) {} + void DeserializeForRendering(Reader & reader) {} + void DeserializeForCrossMwm(Reader & reader) {} + void Clear() {} + void CheckValidSortedUnique() const {} + bool IsEmpty() const { return false; } + /// \brief Sorts all class fields by their ids. + void Sort() {} + void SetGateBestPedestrianSegment(size_t gateIdx, SingleMwmSegment const & s) {} + + std::vector const & GetStops() const { return m_stops; } + std::vector const & GetGates() const { return m_gates; } + std::vector const & GetEdges() const { return m_edges; } + std::vector const & GetTransfers() const { return m_transfers; } + std::vector const & GetLines() const { return m_lines; } + std::vector const & GetShapes() const { return m_shapes; } + std::vector const & GetNetworks() const { return m_networks; } + +private: + DECLARE_VISITOR_AND_DEBUG_PRINT(TransitData, visitor(m_stops, "stops"), visitor(m_gates, "gates"), + visitor(m_edges, "edges"), visitor(m_transfers, "transfers"), + visitor(m_lines, "lines"), visitor(m_shapes, "shapes"), + visitor(m_networks, "networks"), visitor(m_routes, "routes")) + + /// \brief Read a transit table form |src|. + /// \note Before calling any of the method except for ReadHeader() |m_header| has to be filled. + // TODO(o.khlopkova) Add implementation for methods: + void ReadHeader(NonOwningReaderSource & src) {} + void ReadStops(NonOwningReaderSource & src) {} + void ReadGates(NonOwningReaderSource & src) {} + void ReadEdges(NonOwningReaderSource & src) {} + void ReadTransfers(NonOwningReaderSource & src) {} + void ReadLines(NonOwningReaderSource & src) {} + void ReadShapes(NonOwningReaderSource & src) {} + void ReadNetworks(NonOwningReaderSource & src) {} + void ReadRoutes(NonOwningReaderSource & src) {} + + template + void DeserializeWith(Reader & reader, Fn && fn) + { + NonOwningReaderSource src(reader); + ReadHeader(src); + fn(src); + } + + TransitHeader m_header; + std::vector m_networks; + std::vector m_routes; + std::vector m_stops; + std::vector m_gates; + std::vector m_edges; + std::vector m_transfers; + std::vector m_lines; + std::vector m_shapes; +}; +} // namespace experimental +} // namespace transit diff --git a/transit/experimental/transit_types_experimental.cpp b/transit/experimental/transit_types_experimental.cpp new file mode 100644 index 0000000000..726c948976 --- /dev/null +++ b/transit/experimental/transit_types_experimental.cpp @@ -0,0 +1,344 @@ +#include "transit/experimental/transit_types_experimental.hpp" + +#include + +namespace transit +{ +namespace experimental +{ +std::string GetTranslation(Translations const & titles) +{ + CHECK(!titles.empty(), ()); + + // If there is only one language we return title in this only translation. + if (titles.size() == 1) + return titles.begin()->second; + + // Otherwise we try to extract default language for this region. + auto it = titles.find("default"); + if (it != titles.end()) + return it->second; + + // If there is no default language we return one of the represented translations. + return titles.begin()->second; +} + +// SingleMwmSegment -------------------------------------------------------------------------------- +SingleMwmSegment::SingleMwmSegment(FeatureId featureId, uint32_t segmentIdx, bool forward) + : m_featureId(featureId), m_segmentIdx(segmentIdx), m_forward(forward) +{ +} + +// IdBundle ---------------------------------------------------------------------------------------- +IdBundle::IdBundle(bool serializeFeatureIdOnly) : m_serializeFeatureIdOnly(serializeFeatureIdOnly) +{ +} + +IdBundle::IdBundle(FeatureId featureId, OsmId osmId, bool serializeFeatureIdOnly) + : m_featureId(featureId), m_osmId(osmId), m_serializeFeatureIdOnly(serializeFeatureIdOnly) +{ +} + +bool IdBundle::operator<(IdBundle const & rhs) const +{ + CHECK_EQUAL(m_serializeFeatureIdOnly, rhs.m_serializeFeatureIdOnly, ()); + + if (m_serializeFeatureIdOnly) + return m_featureId < rhs.m_featureId; + + if (m_featureId != rhs.m_featureId) + return m_featureId < rhs.m_featureId; + + return m_osmId < rhs.m_osmId; +} + +bool IdBundle::operator==(IdBundle const & rhs) const +{ + CHECK_EQUAL(m_serializeFeatureIdOnly, rhs.m_serializeFeatureIdOnly, ()); + return m_serializeFeatureIdOnly ? m_featureId == rhs.m_featureId + : m_featureId == rhs.m_featureId && m_osmId == rhs.m_osmId; +} + +bool IdBundle::operator!=(IdBundle const & rhs) const { return !(*this == rhs); } + +bool IdBundle::IsValid() const +{ + return m_serializeFeatureIdOnly ? m_featureId != kInvalidFeatureId + : m_featureId != kInvalidFeatureId && m_osmId != kInvalidOsmId; +} + +void IdBundle::SetOsmId(OsmId osmId) { m_osmId = osmId; } + +void IdBundle::SetFeatureId(FeatureId featureId) { m_featureId = featureId; } + +OsmId IdBundle::GetOsmId() const { return m_osmId; } + +FeatureId IdBundle::GetFeatureId() const { return m_featureId; } + +bool IdBundle::SerializeFeatureIdOnly() const { return m_serializeFeatureIdOnly; } + +// Network ----------------------------------------------------------------------------------------- +Network::Network(TransitId id, Translations const & title) : m_id(id), m_title(title) {} + +Network::Network(TransitId id) : m_id(id), m_title{} {} + +bool Network::operator<(Network const & rhs) const { return m_id < rhs.m_id; } + +bool Network::operator==(Network const & rhs) const { return m_id == rhs.m_id; } + +bool Network::IsValid() const { return m_id != kInvalidTransitId; } + +TransitId Network::GetId() const { return m_id; } + +std::string const Network::GetTitle() const { return GetTranslation(m_title); } + +// Route ------------------------------------------------------------------------------------------- +Route::Route(TransitId id, TransitId networkId, std::string const & routeType, + Translations const & title, std::string const & color) + : m_id(id), m_networkId(networkId), m_routeType(routeType), m_title(title), m_color(color) +{ +} + +bool Route::operator<(Route const & rhs) const { return m_id < rhs.m_id; } + +bool Route::operator==(Route const & rhs) const { return m_id == rhs.m_id; } + +bool Route::IsValid() const +{ + return m_id != kInvalidTransitId && m_networkId != kInvalidTransitId && !m_routeType.empty(); +} + +TransitId Route::GetId() const { return m_id; } + +std::string const Route::GetTitle() const { return GetTranslation(m_title); } + +std::string const & Route::GetType() const { return m_routeType; } + +std::string const & Route::GetColor() const { return m_color; } + +TransitId Route::GetNetworkId() const { return m_networkId; } + +// Line -------------------------------------------------------------------------------------------- +Line::Line(TransitId id, TransitId routeId, ShapeLink shapeLink, Translations const & title, + Translations const & number, IdList stopIds, std::vector const & intervals, + osmoh::OpeningHours const & serviceDays) + : m_id(id) + , m_routeId(routeId) + , m_shapeLink(shapeLink) + , m_title(title) + , m_number(number) + , m_stopIds(stopIds) + , m_intervals(intervals) + , m_serviceDays(serviceDays) +{ +} + +bool Line::operator<(Line const & rhs) const { return m_id < rhs.m_id; } + +bool Line::operator==(Line const & rhs) const { return m_id == rhs.m_id; } + +bool Line::IsValid() const +{ + return m_id != kInvalidTransitId && m_routeId != kInvalidTransitId && + m_shapeLink.m_shapeId != kInvalidTransitId && !m_stopIds.empty(); +} + +TransitId Line::GetId() const { return m_id; } + +std::string Line::GetNumber() const { return GetTranslation(m_number); } + +std::string Line::GetTitle() const { return GetTranslation(m_title); } + +TransitId Line::GetRouteId() const { return m_routeId; } + +ShapeLink const & Line::GetShapeLink() const { return m_shapeLink; } + +IdList const & Line::GetStopIds() const { return m_stopIds; } + +std::vector Line::GetIntervals() const { return m_intervals; } + +osmoh::OpeningHours Line::GetServiceDays() const { return m_serviceDays; } + +// Stop -------------------------------------------------------------------------------------------- +Stop::Stop() : m_ids(true /* serializeFeatureIdOnly */) {} + +Stop::Stop(TransitId id, FeatureId featureId, OsmId osmId, Translations const & title, + TimeTable const & timetable, m2::PointD const & point) + : m_id(id) + , m_ids(featureId, osmId, true /* serializeFeatureIdOnly */) + , m_title(title) + , m_timetable(timetable) + , m_point(point) +{ +} + +Stop::Stop(TransitId id) : m_id(id), m_ids(true /* serializeFeatureIdOnly */) {} + +bool Stop::operator<(Stop const & rhs) const +{ + if (m_id != kInvalidTransitId || rhs.m_id != kInvalidTransitId) + return m_id < rhs.m_id; + + return m_ids.GetFeatureId() < rhs.m_ids.GetFeatureId(); +} + +bool Stop::operator==(Stop const & rhs) const +{ + if (m_id != kInvalidTransitId || rhs.m_id != kInvalidTransitId) + return m_id == rhs.m_id; + + return m_ids.GetFeatureId() == rhs.m_ids.GetFeatureId(); +} + +bool Stop::IsValid() const +{ + return ((m_id != kInvalidTransitId) || (m_ids.GetOsmId() != kInvalidOsmId)) && + !m_timetable.empty() && !m_title.empty(); +} + +FeatureId Stop::GetId() const { return m_id; } + +FeatureId Stop::GetFeatureId() const { return m_ids.GetFeatureId(); } + +OsmId Stop::GetOsmId() const { return m_ids.GetOsmId(); } + +std::string Stop::GetTitle() const { return GetTranslation(m_title); } + +TimeTable const & Stop::GetTimeTable() const { return m_timetable; } + +m2::PointD const & Stop::GetPoint() const { return m_point; } + +// Gate -------------------------------------------------------------------------------------------- +Gate::Gate() : m_ids(false /* serializeFeatureIdOnly */) {} + +Gate::Gate(TransitId id, FeatureId featureId, OsmId osmId, bool entrance, bool exit, + std::vector const & weights, m2::PointD const & point) + : m_id(id) + , m_ids(featureId, osmId, false /* serializeFeatureIdOnly */) + , m_entrance(entrance) + , m_exit(exit) + , m_weights(weights) + , m_point(point) +{ +} + +bool Gate::operator<(Gate const & rhs) const +{ + return std::tie(m_id, m_ids, m_entrance, m_exit) < + std::tie(rhs.m_id, rhs.m_ids, rhs.m_entrance, rhs.m_exit); +} + +bool Gate::operator==(Gate const & rhs) const +{ + return std::tie(m_id, m_ids, m_entrance, m_exit) == + std::tie(rhs.m_id, rhs.m_ids, rhs.m_entrance, rhs.m_exit); +} + +bool Gate::IsValid() const +{ + return ((m_id != kInvalidTransitId) || (m_ids.GetOsmId() != kInvalidOsmId)) && + (m_entrance || m_exit) && !m_weights.empty(); +} + +void Gate::SetBestPedestrianSegment(SingleMwmSegment const & s) { m_bestPedestrianSegment = s; }; + +FeatureId Gate::GetFeatureId() const { return m_ids.GetFeatureId(); } + +OsmId Gate::GetOsmId() const { return m_ids.GetOsmId(); } + +SingleMwmSegment const & Gate::GetBestPedestrianSegment() const { return m_bestPedestrianSegment; } + +bool Gate::IsEntrance() const { return m_entrance; } + +bool Gate::IsExit() const { return m_exit; } + +std::vector const & Gate::GetStopsWithWeight() const { return m_weights; } + +m2::PointD const & Gate::GetPoint() const { return m_point; } + +// Edge -------------------------------------------------------------------------------------------- +Edge::Edge(TransitId stop1Id, TransitId stop2Id, EdgeWeight weight, TransitId lineId, bool transfer, + ShapeLink const & shapeLink) + : m_stop1Id(stop1Id) + , m_stop2Id(stop2Id) + , m_weight(weight) + , m_isTransfer(transfer) + , m_lineId(lineId) + , m_shapeLink(shapeLink) +{ +} + +bool Edge::operator<(Edge const & rhs) const +{ + return std::tie(m_stop1Id, m_stop2Id, m_lineId) < + std::tie(rhs.m_stop1Id, rhs.m_stop2Id, rhs.m_lineId); +} + +bool Edge::operator==(Edge const & rhs) const +{ + return std::tie(m_stop1Id, m_stop2Id, m_lineId) == + std::tie(rhs.m_stop1Id, rhs.m_stop2Id, rhs.m_lineId); +} + +bool Edge::operator!=(Edge const & rhs) const { return !(*this == rhs); } + +bool Edge::IsValid() const +{ + if (m_isTransfer && (m_lineId != kInvalidTransitId || m_shapeLink.m_shapeId != kInvalidTransitId)) + return false; + + if (!m_isTransfer && m_lineId == kInvalidTransitId) + return false; + + return m_stop1Id != kInvalidTransitId && m_stop2Id != kInvalidTransitId; +} + +void Edge::SetWeight(EdgeWeight weight) { m_weight = weight; } + +TransitId Edge::GetStop1Id() const { return m_stop1Id; } + +TransitId Edge::GetStop2Id() const { return m_stop2Id; } + +EdgeWeight Edge::GetWeight() const { return m_weight; } + +TransitId Edge::GetLineId() const { return m_lineId; } + +bool Edge::IsTransfer() const { return m_isTransfer; } + +ShapeLink const & Edge::GetShapeLink() const { return m_shapeLink; } + +// Transfer ---------------------------------------------------------------------------------------- +Transfer::Transfer(TransitId id, m2::PointD const & point, IdList const & stopIds) + : m_id(id), m_point(point), m_stopIds(stopIds) +{ +} + +bool Transfer::operator<(Transfer const & rhs) const { return m_id < rhs.m_id; } + +bool Transfer::operator==(Transfer const & rhs) const { return m_id == rhs.m_id; } + +bool Transfer::IsValid() const { return m_id != kInvalidTransitId && m_stopIds.size() > 1; } + +TransitId Transfer::GetId() const { return m_id; } + +m2::PointD const & Transfer::GetPoint() const { return m_point; } + +IdList const & Transfer::GetStopIds() const { return m_stopIds; } + +// Shape ------------------------------------------------------------------------------------------- +Shape::Shape(TransitId id, std::vector const & polyline) + : m_id(id), m_polyline(polyline) +{ +} + +bool Shape::operator<(Shape const & rhs) const { return m_id < rhs.m_id; } + +bool Shape::operator==(Shape const & rhs) const { return m_id == rhs.m_id; } + +bool Shape::IsValid() const { return m_id != kInvalidTransitId && m_polyline.size() > 1; } + +TransitId Shape::GetId() const { return m_id; } + +std::vector const & Shape::GetPolyline() const { return m_polyline; } +} // namespace experimental +} // namespace transit diff --git a/transit/experimental/transit_types_experimental.hpp b/transit/experimental/transit_types_experimental.hpp new file mode 100644 index 0000000000..f9ecaf3ed4 --- /dev/null +++ b/transit/experimental/transit_types_experimental.hpp @@ -0,0 +1,340 @@ +#pragma once + +#include "transit/transit_entities.hpp" + +#include "indexer/scales.hpp" + +#include "geometry/point2d.hpp" + +#include "base/newtype.hpp" +#include "base/visitor.hpp" + +#include +#include +#include +#include +#include +#include + +// This is the implementation of the new transit classes which support not only subway, but also +// public transport types from GTFS. Since it is experimental it exists at one time with +// subway classes for handling networks, stops and other transit entities. When the time comes this +// transit implementation will completely replace the subway classes, they will be removed, and the +// experimental namespace will be also removed. +namespace transit +{ +namespace experimental +{ +#define DECLARE_TRANSIT_TYPES_FRIENDS \ + template \ + friend class Serializer; \ + template \ + friend class Deserializer; \ + template \ + friend class FixedSizeSerializer; \ + template \ + friend class FixedSizeDeserializer; + +using FeatureId = uint32_t; +using OsmId = uint64_t; + +FeatureId constexpr kInvalidFeatureId = std::numeric_limits::max(); +OsmId constexpr kInvalidOsmId = std::numeric_limits::max(); + +class SingleMwmSegment +{ +public: + SingleMwmSegment() = default; + SingleMwmSegment(FeatureId featureId, uint32_t segmentIdx, bool forward); + + FeatureId GetFeatureId() const { return m_featureId; } + uint32_t GetSegmentIdx() const { return m_segmentIdx; } + bool IsForward() const { return m_forward; } + +private: + DECLARE_TRANSIT_TYPES_FRIENDS + DECLARE_VISITOR_AND_DEBUG_PRINT(SingleMwmSegment, visitor(m_featureId, "feature_id"), + visitor(m_segmentIdx, "segment_idx"), + visitor(m_forward, "forward")) + + FeatureId m_featureId = kInvalidFeatureId; + uint32_t m_segmentIdx = 0; + bool m_forward = false; +}; + +/// \brief This class represents osm id and feature id of the same feature. +class IdBundle +{ +public: + explicit IdBundle(bool serializeFeatureIdOnly); + IdBundle(FeatureId featureId, OsmId osmId, bool serializeFeatureIdOnly); + + bool operator<(IdBundle const & rhs) const; + bool operator==(IdBundle const & rhs) const; + bool operator!=(IdBundle const & rhs) const; + bool IsValid() const; + void SetFeatureId(FeatureId featureId); + void SetOsmId(OsmId osmId); + + FeatureId GetFeatureId() const; + OsmId GetOsmId() const; + bool SerializeFeatureIdOnly() const; + +private: + DECLARE_TRANSIT_TYPES_FRIENDS + DECLARE_VISITOR_AND_DEBUG_PRINT(IdBundle, visitor(m_featureId, "feature_id"), + visitor(m_osmId, "osm_id")) + + FeatureId m_featureId = kInvalidFeatureId; + OsmId m_osmId = kInvalidOsmId; + bool m_serializeFeatureIdOnly = true; +}; + +class TransitHeader +{ + // TODO(o.khlopkova) Add body. +}; + +class Network +{ +public: + Network() = default; + Network(TransitId id, Translations const & title); + explicit Network(TransitId id); + + bool operator<(Network const & rhs) const; + bool operator==(Network const & rhs) const; + bool IsValid() const; + + TransitId GetId() const; + std::string const GetTitle() const; + +private: + DECLARE_TRANSIT_TYPES_FRIENDS + DECLARE_VISITOR_AND_DEBUG_PRINT(Network, visitor(m_id, "id"), visitor(m_title, "title")) + + TransitId m_id = kInvalidTransitId; + Translations m_title; +}; + +class Route +{ +public: + Route() = default; + Route(TransitId id, TransitId networkId, std::string const & routeType, + Translations const & title, std::string const & color); + + bool operator<(Route const & rhs) const; + bool operator==(Route const & rhs) const; + bool IsValid() const; + + TransitId GetId() const; + std::string const GetTitle() const; + std::string const & GetType() const; + std::string const & GetColor() const; + TransitId GetNetworkId() const; + +private: + DECLARE_TRANSIT_TYPES_FRIENDS + DECLARE_VISITOR_AND_DEBUG_PRINT(Route, visitor(m_id, "id"), visitor(m_networkId, "network_id"), + visitor(m_routeType, "type"), visitor(m_title, "title"), + visitor(m_color, "color")) + TransitId m_id = kInvalidTransitId; + TransitId m_networkId = kInvalidTransitId; + std::string m_routeType; + Translations m_title; + std::string m_color; +}; + +class Line +{ +public: + Line() = default; + Line(TransitId id, TransitId routeId, ShapeLink shapeLink, Translations const & title, + Translations const & number, IdList stopIds, std::vector const & intervals, + osmoh::OpeningHours const & serviceDays); + + bool operator<(Line const & rhs) const; + bool operator==(Line const & rhs) const; + bool IsValid() const; + + TransitId GetId() const; + std::string GetNumber() const; + std::string GetTitle() const; + TransitId GetRouteId() const; + ShapeLink const & GetShapeLink() const; + IdList const & GetStopIds() const; + std::vector GetIntervals() const; + osmoh::OpeningHours GetServiceDays() const; + +private: + DECLARE_TRANSIT_TYPES_FRIENDS + DECLARE_VISITOR_AND_DEBUG_PRINT(Line, visitor(m_id, "id"), visitor(m_routeId, "route_id"), + visitor(m_shapeLink, "shape_link"), visitor(m_title, "title"), + visitor(m_number, "number"), visitor(m_stopIds, "stop_ids"), + visitor(m_intervals, "intervals"), + visitor(m_serviceDays.GetRule(), "service_days")) + TransitId m_id = kInvalidTransitId; + TransitId m_routeId = kInvalidTransitId; + ShapeLink m_shapeLink; + Translations m_title; + Translations m_number; + IdList m_stopIds; + std::vector m_intervals; + osmoh::OpeningHours m_serviceDays; +}; + +class Stop +{ +public: + Stop(); + Stop(TransitId id, FeatureId featureId, OsmId osmId, Translations const & title, + TimeTable const & timetable, m2::PointD const & point); + explicit Stop(TransitId id); + + bool operator<(Stop const & rhs) const; + bool operator==(Stop const & rhs) const; + bool IsValid() const; + + FeatureId GetId() const; + FeatureId GetFeatureId() const; + OsmId GetOsmId() const; + std::string GetTitle() const; + TimeTable const & GetTimeTable() const; + m2::PointD const & GetPoint() const; + +private: + DECLARE_TRANSIT_TYPES_FRIENDS + // TODO(o.khlopkova) add visitor for |m_timetable|. + DECLARE_VISITOR_AND_DEBUG_PRINT(Stop, visitor(m_id, "id"), visitor(m_ids, "osm_id"), + visitor(m_title, "title"), visitor(m_point, "point")) + + TransitId m_id = kInvalidTransitId; + IdBundle m_ids; + Translations m_title; + TimeTable m_timetable; + m2::PointD m_point; +}; + +class Gate +{ +public: + Gate(); + Gate(TransitId id, FeatureId featureId, OsmId osmId, bool entrance, bool exit, + std::vector const & weights, m2::PointD const & point); + + bool operator<(Gate const & rhs) const; + bool operator==(Gate const & rhs) const; + bool IsValid() const; + void SetBestPedestrianSegment(SingleMwmSegment const & s); + + FeatureId GetFeatureId() const; + OsmId GetOsmId() const; + SingleMwmSegment const & GetBestPedestrianSegment() const; + bool IsEntrance() const; + bool IsExit() const; + std::vector const & GetStopsWithWeight() const; + m2::PointD const & GetPoint() const; + +private: + DECLARE_TRANSIT_TYPES_FRIENDS + DECLARE_VISITOR_AND_DEBUG_PRINT(Gate, visitor(m_id, "id"), visitor(m_ids, "ids"), + visitor(m_bestPedestrianSegment, "best_pedestrian_segment"), + visitor(m_entrance, "entrance"), visitor(m_exit, "exit"), + visitor(m_weights, "weights"), visitor(m_point, "point")) + + TransitId m_id = kInvalidTransitId; + // |m_ids| contains feature id of a feature which represents gates. Usually it's a + // point feature. + IdBundle m_ids; + // |m_bestPedestrianSegment| is a segment which can be used for pedestrian routing to leave and + // enter the gate. The segment may be invalid because of map date. If so there's no pedestrian + // segment which can be used to reach the gate. + SingleMwmSegment m_bestPedestrianSegment; + bool m_entrance = true; + bool m_exit = true; + std::vector m_weights; + m2::PointD m_point; +}; + +class Edge +{ +public: + Edge() = default; + Edge(TransitId stop1Id, TransitId stop2Id, EdgeWeight weight, TransitId lineId, bool transfer, + ShapeLink const & shapeLink); + + bool operator<(Edge const & rhs) const; + bool operator==(Edge const & rhs) const; + bool operator!=(Edge const & rhs) const; + bool IsValid() const; + void SetWeight(EdgeWeight weight); + + TransitId GetStop1Id() const; + TransitId GetStop2Id() const; + EdgeWeight GetWeight() const; + TransitId GetLineId() const; + bool IsTransfer() const; + ShapeLink const & GetShapeLink() const; + +private: + DECLARE_TRANSIT_TYPES_FRIENDS + DECLARE_VISITOR_AND_DEBUG_PRINT(Edge, visitor(m_stop1Id, "stop1_id"), + visitor(m_stop2Id, "stop2_id"), visitor(m_weight, "weight"), + visitor(m_isTransfer, "is_transfer"), + visitor(m_lineId, "line_id"), visitor(m_shapeLink, "shape_link")) + + TransitId m_stop1Id = kInvalidTransitId; + TransitId m_stop2Id = kInvalidTransitId; + EdgeWeight m_weight = 0; + bool m_isTransfer = false; + TransitId m_lineId = kInvalidTransitId; + ShapeLink m_shapeLink; +}; + +class Transfer +{ +public: + Transfer() = default; + Transfer(TransitId id, m2::PointD const & point, IdList const & stopIds); + + bool operator<(Transfer const & rhs) const; + bool operator==(Transfer const & rhs) const; + bool IsValid() const; + + TransitId GetId() const; + m2::PointD const & GetPoint() const; + IdList const & GetStopIds() const; + +private: + DECLARE_TRANSIT_TYPES_FRIENDS + DECLARE_VISITOR_AND_DEBUG_PRINT(Transfer, visitor(m_id, "id"), visitor(m_point, "point"), + visitor(m_stopIds, "stop_ids")) + + TransitId m_id = kInvalidTransitId; + m2::PointD m_point; + IdList m_stopIds; +}; + +class Shape +{ +public: + Shape() = default; + Shape(TransitId id, std::vector const & polyline); + + bool operator<(Shape const & rhs) const; + bool operator==(Shape const & rhs) const; + bool IsValid() const; + + TransitId GetId() const; + std::vector const & GetPolyline() const; + +private: + DECLARE_TRANSIT_TYPES_FRIENDS + DECLARE_VISITOR_AND_DEBUG_PRINT(Shape, visitor(m_id, "id"), visitor(m_polyline, "polyline")) + + TransitId m_id; + std::vector m_polyline; +}; +} // namespace experimental +} // namespace transit diff --git a/transit/transit_entities.hpp b/transit/transit_entities.hpp new file mode 100644 index 0000000000..325042c8b9 --- /dev/null +++ b/transit/transit_entities.hpp @@ -0,0 +1,83 @@ +#pragma once + +#include "base/macros.hpp" +#include "base/newtype.hpp" +#include "base/visitor.hpp" + +#include "defines.hpp" + +#include +#include +#include +#include +#include + +#include "3party/opening_hours/opening_hours.hpp" + +namespace routing +{ +inline double constexpr kTransitMaxSpeedKMpH = 400.0; +} // namespace routing + +namespace transit +{ +// File names for saving resulting data exported from GTFS. +inline std::string const kTransitFileExtension = std::string(TRANSIT_FILE_EXTENSION); +inline std::string const kNetworksFile = "networks" + kTransitFileExtension; +inline std::string const kRoutesFile = "routes" + kTransitFileExtension; +inline std::string const kLinesFile = "lines" + kTransitFileExtension; +inline std::string const kShapesFile = "shapes" + kTransitFileExtension; +inline std::string const kStopsFile = "stops" + kTransitFileExtension; +inline std::string const kEdgesFile = "edges" + kTransitFileExtension; +inline std::string const kEdgesTransferFile = "edges_transfer" + kTransitFileExtension; +inline std::string const kTransfersFile = "transfers" + kTransitFileExtension; +inline std::string const kGatesFile = "gates" + kTransitFileExtension; + +// Unique id for transit entities. It is generated by gtfs_converter and is persistent between +// re-runs. Generated based on the unique string hash of the GTFS entity. Lies in the interval +// |routing::FakeFeatureIds::IsTransitFeature()|. If the GTFS entity is renamed or the new GTFS +// feed is added the new id is generated by |IdGenerator::MakeId()|. +using TransitId = uint32_t; +inline TransitId constexpr kInvalidTransitId = std::numeric_limits::max(); + +// Mapping of language id to text. Language id exists in |StringUtf8Multilang::kLanguages|. +using Translations = std::unordered_map; + +struct TimeFromGateToStop +{ + DECLARE_VISITOR_AND_DEBUG_PRINT(TimeFromGateToStop, visitor(m_stopId, "stopId"), + visitor(m_timeSeconds, "timeSeconds")) + + TransitId m_stopId = kInvalidTransitId; + size_t m_timeSeconds = 0; +}; + +struct LineInterval +{ + DECLARE_VISITOR_AND_DEBUG_PRINT(LineInterval, visitor(m_headwayS, "headwayS"), + visitor(m_timeIntervals.GetRule(), "timeIntervals")) + // Service interval in seconds between departures from the same stop (headway) for the line, + // during the time interval specified by |m_timeIntervals|. + size_t m_headwayS = 0; + // Time interval for the |m_headwayS|. Multiple headways for the same trip are allowed, but may + // not overlap in time. + osmoh::OpeningHours m_timeIntervals; +}; + +using LineIntervals = std::vector; +using IdList = std::vector; +using TimeTable = std::unordered_map; +using EdgeWeight = uint32_t; + +// Link to the shape: shape id and indexes in the corresponding polyline. +struct ShapeLink +{ + DECLARE_VISITOR_AND_DEBUG_PRINT(ShapeLink, visitor(m_shapeId, "id"), + visitor(m_startIndex, "startIndex"), + visitor(m_endIndex, "endIndex")) + + TransitId m_shapeId = kInvalidTransitId; + size_t m_startIndex = 0; + size_t m_endIndex = 0; +}; +} // namespace transit diff --git a/transit/transit_speed_limits.hpp b/transit/transit_speed_limits.hpp deleted file mode 100644 index 6f7ddb8688..0000000000 --- a/transit/transit_speed_limits.hpp +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -namespace routing -{ -namespace transit -{ -double constexpr kTransitMaxSpeedKMpH = 400.0; -} // namespace transit -} // namespace routing diff --git a/transit/world_feed/world_feed.hpp b/transit/world_feed/world_feed.hpp index d6363aa6bd..2ad42f4a8e 100644 --- a/transit/world_feed/world_feed.hpp +++ b/transit/world_feed/world_feed.hpp @@ -1,6 +1,8 @@ #pragma once + #include "generator/affiliation.hpp" +#include "transit/transit_entities.hpp" #include "transit/world_feed/color_picker.hpp" #include "geometry/mercator.hpp" @@ -21,24 +23,6 @@ namespace transit { -// File names for saving resulting data exported from GTFS. -inline std::string const kTransitFileExtension = std::string(TRANSIT_FILE_EXTENSION); -inline std::string const kNetworksFile = "networks" + kTransitFileExtension; -inline std::string const kRoutesFile = "routes" + kTransitFileExtension; -inline std::string const kLinesFile = "lines" + kTransitFileExtension; -inline std::string const kShapesFile = "shapes" + kTransitFileExtension; -inline std::string const kStopsFile = "stops" + kTransitFileExtension; -inline std::string const kEdgesFile = "edges" + kTransitFileExtension; -inline std::string const kEdgesTransferFile = "edges_transfer" + kTransitFileExtension; -inline std::string const kTransfersFile = "transfers" + kTransitFileExtension; -inline std::string const kGatesFile = "gates" + kTransitFileExtension; - -// Unique id persistent between re-runs. Generated based on the unique string hash of the -// GTFS entity. Lies in the interval |routing::FakeFeatureIds::IsTransitFeature()|. -// If the GTFS entity is renamed or the new GTFS feed is added the new id is generated by -// |IdGenerator::MakeId()|. -using TransitId = uint32_t; - // Generates globally unique TransitIds mapped to the GTFS entities hashes. class IdGenerator { @@ -60,9 +44,6 @@ private: using IdSet = std::unordered_set; -// Mapping of language id to text. -using Translations = std::unordered_map; - struct Networks { void Write(IdSet const & ids, std::ofstream & stream) const; @@ -86,23 +67,6 @@ struct Routes std::unordered_map m_data; }; -struct LineInterval -{ - size_t m_headwayS = 0; - osmoh::OpeningHours m_timeIntervals; -}; - -using LineIntervals = std::vector; -using IdList = std::vector; - -// Link to the shape: its id and indexes in the corresponding polyline. -struct ShapeLink -{ - TransitId m_shapeId = 0; - size_t m_startIndex = 0; - size_t m_endIndex = 0; -}; - struct LineData { TransitId m_routeId = 0; @@ -155,7 +119,7 @@ struct StopData Translations m_title; // If arrival time at a specific stop for a specific trip on a route is not available, // |m_timetable| can be left empty. - std::unordered_map m_timetable; + TimeTable m_timetable; // Field not intended for dumping to json: std::string m_gtfsParentId; @@ -190,7 +154,7 @@ using IdEdgeSet = std::unordered_set; struct EdgeData { ShapeLink m_shapeLink; - size_t m_weight = 0; + EdgeWeight m_weight = 0; }; struct Edges @@ -238,12 +202,6 @@ struct Transfers std::unordered_map m_data; }; -struct TimeFromGateToStop -{ - TransitId m_stopId = 0; - size_t m_timeSeconds = 0; -}; - struct GateData { bool m_isEntrance = false;