// Copyright 2018, University of Freiburg, // Chair of Algorithms and Data Structures. // Authors: Patrick Brosi #include #include #include #include "TripTrie.h" #include "ad/cppgtfs/gtfs/Feed.h" #include "pfaedle/gtfs/Feed.h" #include "pfaedle/gtfs/StopTime.h" using pfaedle::gtfs::Trip; using pfaedle::router::TripTrie; // _____________________________________________________________________________ template bool TripTrie::addTrip(TRIP* trip, const RoutingAttrs& rAttrs, bool timeEx, bool degen) { if (!degen) return add(trip, rAttrs, timeEx); // check if trip is already fully and uniquely contained, if not, fail size_t existing = get(trip, timeEx); if (existing && _nds[existing].childs.size() == 0) { _tripNds[trip] = existing; _ndTrips[existing].push_back(trip); return true; } else { return false; } } // _____________________________________________________________________________ template bool TripTrie::add(TRIP* trip, const RoutingAttrs& rAttrs, bool timeEx) { if (trip->getStopTimes().size() == 0) return false; int startSecs = trip->getStopTimes().front().getDepartureTime().seconds(); size_t curNdId = 0; for (size_t stId = 0; stId < trip->getStopTimes().size(); stId++) { const auto st = trip->getStopTimes()[stId]; std::string name = st.getStop()->getName(); std::string platform = st.getStop()->getPlatformCode(); POINT pos = util::geo::latLngToWebMerc(st.getStop()->getLat(), st.getStop()->getLng()); if (stId > 0) { int arrTime = st.getArrivalTime().seconds() - startSecs; size_t arrChild = getMatchChild(curNdId, name, platform, pos, arrTime, timeEx); if (arrChild) { curNdId = arrChild; _nds[arrChild].accTime += arrTime; _nds[arrChild].trips += 1; _nds[arrChild].rAttrs.merge(rAttrs); } else { curNdId = insert(st.getStop(), rAttrs, pos, arrTime, true, curNdId); } } if (stId < trip->getStopTimes().size() - 1) { int depTime = st.getDepartureTime().seconds() - startSecs; size_t depChild = getMatchChild(curNdId, name, platform, pos, depTime, timeEx); if (depChild) { curNdId = depChild; _nds[depChild].accTime += depTime; _nds[depChild].trips += 1; _nds[depChild].rAttrs.merge(rAttrs); } else { if (stId == 0 && _tripNds.size() > 0) return false; curNdId = insert(st.getStop(), rAttrs, pos, depTime, false, curNdId); } } } // curNdId is now the last matching node, insert the trip here _tripNds[trip] = curNdId; _ndTrips[curNdId].push_back(trip); return true; } // _____________________________________________________________________________ template size_t TripTrie::get(TRIP* trip, bool timeEx) { if (trip->getStopTimes().size() == 0) return false; int startSecs = trip->getStopTimes().front().getDepartureTime().seconds(); size_t curNdId = 0; for (size_t stId = 0; stId < trip->getStopTimes().size(); stId++) { const auto st = trip->getStopTimes()[stId]; std::string name = st.getStop()->getName(); std::string platform = st.getStop()->getPlatformCode(); POINT pos = util::geo::latLngToWebMerc(st.getStop()->getLat(), st.getStop()->getLng()); if (stId > 0) { int arrTime = st.getArrivalTime().seconds() - startSecs; size_t arrChild = getMatchChild(curNdId, name, platform, pos, arrTime, timeEx); if (arrChild) { curNdId = arrChild; } else { return 0; } } if (stId < trip->getStopTimes().size() - 1) { int depTime = st.getDepartureTime().seconds() - startSecs; size_t depChild = getMatchChild(curNdId, name, platform, pos, depTime, timeEx); if (depChild) { curNdId = depChild; } else { return 0; } } } return curNdId; } // _____________________________________________________________________________ template size_t TripTrie::insert(const ad::cppgtfs::gtfs::Stop* stop, const RoutingAttrs& rAttrs, const POINT& pos, int time, bool arr, size_t parent) { _nds.emplace_back(TripTrieNd{stop, stop->getName(), stop->getPlatformCode(), pos, stop->getLat(), stop->getLng(), time, arr, time, 1, parent, {}, rAttrs}); _nds[parent].childs.push_back(_nds.size() - 1); return _nds.size() - 1; } // _____________________________________________________________________________ template const std::vector& TripTrie::getNds() const { return _nds; } // _____________________________________________________________________________ template size_t TripTrie::getMatchChild(size_t parentNid, const std::string& stopName, const std::string& platform, POINT pos, int time, bool timeEx) const { for (size_t child : _nds[parentNid].childs) { // TODO(patrick): use similarity classification here? if (_nds[child].stopName == stopName && _nds[child].platform == platform && util::geo::dist(_nds[child].pos, pos) < 1 && (!timeEx || _nds[child].time == time)) { return child; } } return 0; } // _____________________________________________________________________________ template void TripTrie::toDot(std::ostream& os, const std::string& rootName, size_t gid) const { os << "digraph triptrie" << gid << " {"; for (size_t nid = 0; nid < _nds.size(); nid++) { std::string color = "white"; if (_ndTrips.count(nid)) color = "red"; if (nid == 0) { os << "\"" << gid << ":0\" [label=\"" << rootName << "\"];\n"; } else { os << "\"" << gid << ":" << nid << "\" [shape=\"box\" style=\"filled\" fillcolor=\"" << color << "\" label=\"#" << nid << ", " << _nds[nid].stopName << "@" << util::geo::getWKT(_nds[nid].pos) << " t=" << _nds[nid].time << "\"];\n"; } } for (size_t nid = 0; nid < _nds.size(); nid++) { for (size_t child : _nds[nid].childs) { os << "\"" << gid << ":" << nid << "\" -> \"" << gid << ":" << child << "\";\n"; } } os << "}"; } // _____________________________________________________________________________ template const std::map>& TripTrie::getNdTrips() const { return _ndTrips; } // _____________________________________________________________________________ template const pfaedle::router::TripTrieNd& TripTrie::getNd(size_t nid) const { return _nds[nid]; }