#include "engine/engine.h" #include "utility/utility.h" #include #include #include #include #include #include namespace CityFlow { Engine::Engine(const std::string &configFile, int threadNum) : threadNum(threadNum), startBarrier(threadNum + 1), endBarrier(threadNum + 1) { for (int i = 0; i < threadNum; i++) { threadVehiclePool.emplace_back(); threadRoadPool.emplace_back(); threadIntersectionPool.emplace_back(); threadDrivablePool.emplace_back(); } bool success = loadConfig(configFile); if (!success) { std::cerr << "load config failed!" << std::endl; } for (int i = 0; i < threadNum; i++) { threadPool.emplace_back(&Engine::threadController, this, std::ref(threadVehiclePool[i]), std::ref(threadRoadPool[i]), std::ref(threadIntersectionPool[i]), std::ref(threadDrivablePool[i])); } } bool Engine::loadConfig(const std::string &configFile) { rapidjson::Document document; if (!readJsonFromFile(configFile, document)) { std::cerr << "cannot open config file!" << std::endl; return false; } if (!document.IsObject()) { std::cerr << "wrong format of config file" << std::endl; return false; } try { interval = getJsonMember("interval", document); warnings = false; rlTrafficLight = getJsonMember("rlTrafficLight", document); laneChange = getJsonMember("laneChange", document, false); seed = getJsonMember("seed", document); rnd.seed(seed); dir = getJsonMember("dir", document); std::string roadnetFile = getJsonMember("roadnetFile", document); std::string flowFile = getJsonMember("flowFile", document); if (!loadRoadNet(dir + roadnetFile)) { std::cerr << "loading roadnet file error!" << std::endl; return false; } if (!loadFlow(dir + flowFile)) { std::cerr << "loading flow file error!" << std::endl; return false; } if (warnings) checkWarning(); saveReplayInConfig = saveReplay = getJsonMember("saveReplay", document); if (saveReplay) { std::string roadnetLogFile = getJsonMember("roadnetLogFile", document); std::string replayLogFile = getJsonMember("replayLogFile", document); setLogFile(dir + roadnetLogFile, dir + replayLogFile); } } catch (const JsonFormatError &e) { std::cerr << e.what() << std::endl; return false; } stepLog = ""; return true; } bool Engine::loadRoadNet(const std::string &jsonFile) { bool ans = roadnet.loadFromJson(jsonFile); int cnt = 0; for (Road &road : roadnet.getRoads()) { threadRoadPool[cnt].push_back(&road); cnt = (cnt + 1) % threadNum; } for (Intersection &intersection : roadnet.getIntersections()) { threadIntersectionPool[cnt].push_back(&intersection); cnt = (cnt + 1) % threadNum; } for (Drivable *drivable : roadnet.getDrivables()) { threadDrivablePool[cnt].push_back(drivable); cnt = (cnt + 1) % threadNum; } jsonRoot.SetObject(); jsonRoot.AddMember("static", roadnet.convertToJson(jsonRoot.GetAllocator()), jsonRoot.GetAllocator()); return ans; } bool Engine::loadFlow(const std::string &jsonFilename) { rapidjson::Document root; if (!readJsonFromFile(jsonFilename, root)) { std::cerr << "cannot open flow file!" << std::endl; return false; } std::list path; try { if (!root.IsArray()) throw JsonTypeError("flow file", "array"); for (rapidjson::SizeType i = 0; i < root.Size(); i++) { path.emplace_back("flow[" + std::to_string(i) + "]"); rapidjson::Value &flow = root[i]; std::vector roads; const auto &routes = getJsonMemberArray("route", flow); roads.reserve(routes.Size()); for (auto &route: routes.GetArray()) { path.emplace_back("route[" + std::to_string(roads.size()) + "]"); if (!route.IsString()) throw JsonTypeError("route", "string"); std::string roadName = route.GetString(); auto road = roadnet.getRoadById(roadName); if (!road) throw JsonFormatError("No such road: " + roadName); roads.push_back(road); path.pop_back(); } auto route = std::make_shared(roads); VehicleInfo vehicleInfo; const auto &vehicle = getJsonMemberObject("vehicle", flow); vehicleInfo.len = getJsonMember("length", vehicle); vehicleInfo.width = getJsonMember("width", vehicle); vehicleInfo.maxPosAcc = getJsonMember("maxPosAcc", vehicle); vehicleInfo.maxNegAcc = getJsonMember("maxNegAcc", vehicle); vehicleInfo.usualPosAcc = getJsonMember("usualPosAcc", vehicle); vehicleInfo.usualNegAcc = getJsonMember("usualNegAcc", vehicle); vehicleInfo.minGap = getJsonMember("minGap", vehicle); vehicleInfo.maxSpeed = getJsonMember("maxSpeed", vehicle); vehicleInfo.headwayTime = getJsonMember("headwayTime", vehicle); vehicleInfo.route = route; int startTime = getJsonMember("startTime", flow, 0); int endTime = getJsonMember("endTime", flow, -1); Flow newFlow(vehicleInfo, getJsonMember("interval", flow), this, startTime, endTime, "flow_" + std::to_string(i)); flows.push_back(newFlow); path.pop_back(); } assert(path.empty()); } catch (const JsonFormatError &e) { std::cerr << "Error occurred when reading flow file" << std::endl; for (const auto &node : path) { std::cerr << "/" << node; } std::cerr << " " << e.what() << std::endl; return false; } return true; } bool Engine::checkWarning() { bool result = true; if (interval < 0.2 || interval > 1.5) { std::cerr << "Deprecated time interval, recommended interval between 0.2 and 1.5" << std::endl; result = false; } for (Lane *lane : roadnet.getLanes()) { if (lane->getLength() < 50) { std::cerr << "Deprecated road length, recommended road length at least 50 meters" << std::endl; result = false; } if (lane->getMaxSpeed() > 30) { std::cerr << "Deprecated road max speed, recommended max speed at most 30 meters/s" << std::endl; result = false; } } return result; } void Engine::vehicleControl(Vehicle &vehicle, std::vector> &buffer) { double nextSpeed; if (vehicle.hasSetSpeed()) nextSpeed = vehicle.getBufferSpeed(); else nextSpeed = vehicle.getNextSpeed(interval).speed; if (laneChange) { Vehicle * partner = vehicle.getPartner(); if (partner != nullptr && !partner->hasSetSpeed()){ double partnerSpeed = partner->getNextSpeed(interval).speed; nextSpeed = min2double(nextSpeed, partnerSpeed); partner->setSpeed(nextSpeed); if (partner->hasSetEnd()) vehicle.setEnd(true); } } if (vehicle.getPartner()) { assert(vehicle.getDistance() == vehicle.getPartner()->getDistance()); } double deltaDis, speed = vehicle.getSpeed(); if (nextSpeed < 0) { deltaDis = 0.5 * speed * speed / vehicle.getMaxNegAcc(); nextSpeed = 0; } else { deltaDis = (speed + nextSpeed) * interval / 2; } vehicle.setSpeed(nextSpeed); vehicle.setDeltaDistance(deltaDis); if (laneChange) { if (!vehicle.isReal() && vehicle.getChangedDrivable() != nullptr) { vehicle.abortLaneChange(); } if (vehicle.isChanging()) { assert(vehicle.isReal()); int dir = vehicle.getLaneChangeDirection(); double newOffset = fabs(vehicle.getOffset() + max2double(0.2 * nextSpeed, 1) * interval * dir); newOffset = min2double(newOffset, vehicle.getMaxOffset()); vehicle.setOffset(newOffset * dir); if (newOffset >= vehicle.getMaxOffset()) { std::lock_guard guard(lock); vehicleMap.erase(vehicle.getPartner()->getId()); vehicleMap[vehicle.getId()] = vehicle.getPartner(); vehicle.finishChanging(); } } } if (!vehicle.hasSetEnd() && vehicle.hasSetDrivable()) { buffer.emplace_back(&vehicle, vehicle.getBufferDis()); } } void Engine::threadController(std::set &vehicles, std::vector &roads, std::vector &intersections, std::vector &drivables) { while (!finished) { threadPlanRoute(roads); if (laneChange) { threadInitSegments(roads); threadPlanLaneChange(vehicles); threadUpdateLeaderAndGap(drivables); } threadNotifyCross(intersections); threadGetAction(vehicles); threadUpdateLocation(drivables); threadUpdateAction(vehicles); threadUpdateLeaderAndGap(drivables); } } void Engine::threadPlanRoute(const std::vector &roads) { startBarrier.wait(); for (auto &road : roads) { for (auto &vehicle : road->getPlanRouteBuffer()) { vehicle->updateRoute(); } } endBarrier.wait(); } void Engine::threadUpdateLocation(const std::vector &drivables) { startBarrier.wait(); for (Drivable *drivable : drivables) { auto &vehicles = drivable->getVehicles(); auto vehicleItr = vehicles.begin(); while (vehicleItr != vehicles.end()) { Vehicle *vehicle = *vehicleItr; if ((vehicle->getChangedDrivable()) != nullptr || vehicle->hasSetEnd()) { vehicleItr = vehicles.erase(vehicleItr); }else{ vehicleItr++; } if (vehicle->hasSetEnd()) { std::lock_guard guard(lock); vehicleRemoveBuffer.insert(vehicle); if (!vehicle->getLaneChange()->hasFinished()) { vehicleMap.erase(vehicle->getId()); finishedVehicleCnt += 1; cumulativeTravelTime += getCurrentTime() - vehicle->getEnterTime(); } auto iter = vehiclePool.find(vehicle->getPriority()); threadVehiclePool[iter->second.second].erase(vehicle); // assert(vehicle->getPartner() == nullptr); delete vehicle; vehiclePool.erase(iter); activeVehicleCount--; } } } endBarrier.wait(); } void Engine::threadNotifyCross(const std::vector &intersections) { //TODO: iterator for laneLink startBarrier.wait(); for (Intersection *intersection : intersections) for (Cross &cross : intersection->getCrosses()) cross.clearNotify(); for (Intersection *intersection : intersections) for (LaneLink *laneLink : intersection->getLaneLinks()) { // XXX: no cross in laneLink? const auto &crosses = laneLink->getCrosses(); auto rIter = crosses.rbegin(); // first check the vehicle on the end lane Vehicle *vehicle = laneLink->getEndLane()->getLastVehicle(); if (vehicle && static_cast(vehicle->getPrevDrivable()) == laneLink) { double vehDistance = vehicle->getDistance() - vehicle->getLen(); while (rIter != crosses.rend()) { double crossDistance = laneLink->getLength() - (*rIter)->getDistanceByLane(laneLink); if (crossDistance + vehDistance < (*rIter)->getLeaveDistance()) { (*rIter)->notify(laneLink, vehicle, -(vehicle->getDistance() + crossDistance)); ++rIter; } else break; } } // check each vehicle on laneLink for (Vehicle *linkVehicle : laneLink->getVehicles()) { double vehDistance = linkVehicle->getDistance(); while (rIter != crosses.rend()) { double crossDistance = (*rIter)->getDistanceByLane(laneLink); if (vehDistance > crossDistance) { if (vehDistance - crossDistance - linkVehicle->getLen() <= (*rIter)->getLeaveDistance()) { (*rIter)->notify(laneLink, linkVehicle, crossDistance - vehDistance); } else break; } else { (*rIter)->notify(laneLink, linkVehicle, crossDistance - vehDistance); } ++rIter; } } // check vehicle on the incoming lane vehicle = laneLink->getStartLane()->getFirstVehicle(); if (vehicle && static_cast(vehicle->getNextDrivable()) == laneLink && laneLink->isAvailable()) { double vehDistance = laneLink->getStartLane()->getLength() - vehicle->getDistance(); while (rIter != crosses.rend()) { (*rIter)->notify(laneLink, vehicle, vehDistance + (*rIter)->getDistanceByLane(laneLink)); ++rIter; } } } endBarrier.wait(); } void Engine::threadPlanLaneChange(const std::set &vehicles) { startBarrier.wait(); std::vector buffer; for (auto vehicle : vehicles) if (vehicle->isRunning() && vehicle->isReal()) { vehicle->makeLaneChangeSignal(interval); if (vehicle->planLaneChange()){ buffer.emplace_back(vehicle); } } { std::lock_guard guard(lock); laneChangeNotifyBuffer.insert(laneChangeNotifyBuffer.end(), buffer.begin(), buffer.end()); } endBarrier.wait(); } void Engine::threadInitSegments(const std::vector &roads) { startBarrier.wait(); for (Road *road : roads) for (Lane &lane : road->getLanes()) { lane.initSegments(); } endBarrier.wait(); } void Engine::threadGetAction(std::set &vehicles) { startBarrier.wait(); std::vector> buffer; for (auto vehicle: vehicles) if (vehicle->isRunning()) vehicleControl(*vehicle, buffer); { std::lock_guard guard(lock); pushBuffer.insert(pushBuffer.end(), buffer.begin(), buffer.end()); } endBarrier.wait(); } void Engine::threadUpdateAction(std::set &vehicles) { startBarrier.wait(); for (auto vehicle: vehicles) if (vehicle->isRunning()) { if (vehicleRemoveBuffer.count(vehicle->getBufferBlocker())){ vehicle->setBlocker(nullptr); } vehicle->update(); vehicle->clearSignal(); } endBarrier.wait(); } void Engine::threadUpdateLeaderAndGap(const std::vector &drivables) { startBarrier.wait(); for (Drivable *drivable : drivables) { Vehicle *leader = nullptr; for (Vehicle *vehicle : drivable->getVehicles()) { vehicle->updateLeaderAndGap(leader); leader = vehicle; } if (drivable->isLane()){ static_cast(drivable)->updateHistory(); } } endBarrier.wait(); } void Engine::planLaneChange() { startBarrier.wait(); endBarrier.wait(); scheduleLaneChange(); } void Engine::planRoute() { startBarrier.wait(); endBarrier.wait(); for (auto &road : roadnet.getRoads()) { for (auto &vehicle : road.getPlanRouteBuffer()) if (vehicle->isRouteValid()) { vehicle->setFirstDrivable(); vehicle->getCurLane()->pushWaitingVehicle(vehicle); }else { Flow *flow = vehicle->getFlow(); if (flow) flow->setValid(false); //remove this vehicle auto iter = vehiclePool.find(vehicle->getPriority()); threadVehiclePool[iter->second.second].erase(vehicle); delete vehicle; vehiclePool.erase(iter); } road.clearPlanRouteBuffer(); } } void Engine::getAction() { startBarrier.wait(); endBarrier.wait(); } void Engine::updateLocation() { startBarrier.wait(); endBarrier.wait(); std::sort(pushBuffer.begin(), pushBuffer.end(), vehicleCmp); for (auto &vehiclePair : pushBuffer) { Vehicle *vehicle = vehiclePair.first; Drivable *drivable = vehicle->getChangedDrivable(); if (drivable != nullptr) { drivable->pushVehicle(vehicle); if (drivable->isLaneLink()) { vehicle->setEnterLaneLinkTime(step); } else { vehicle->setEnterLaneLinkTime(std::numeric_limits::max()); } } } pushBuffer.clear(); } void Engine::updateAction() { startBarrier.wait(); endBarrier.wait(); vehicleRemoveBuffer.clear(); } void Engine::handleWaiting() { for (Lane *lane : roadnet.getLanes()) { auto &buffer = lane->getWaitingBuffer(); if (buffer.empty()) continue; auto &vehicle = buffer.front(); if (lane->available(vehicle)) { vehicle->setRunning(true); activeVehicleCount += 1; Vehicle * tail = lane->getLastVehicle(); lane->pushVehicle(vehicle); vehicle->updateLeaderAndGap(tail); buffer.pop_front(); } } } void Engine::updateLog() { std::string result; for (const Vehicle* vehicle: getRunningVehicles()) { Point pos = vehicle->getPoint(); Point dir = vehicle->getCurDrivable()->getDirectionByDistance(vehicle->getDistance()); int lc = vehicle->lastLaneChangeDirection(); result.append( double2string(pos.x) + " " + double2string(pos.y) + " " + double2string(atan2(dir.y, dir.x)) + " " + vehicle->getId() + " " + std::to_string(lc) + " " + double2string(vehicle->getLen()) + " " + double2string(vehicle->getWidth()) + ","); } result.append(";"); for (const Road &road : roadnet.getRoads()) { if (road.getEndIntersection().isVirtualIntersection()) continue; result.append(road.getId()); for (const Lane &lane : road.getLanes()) { if (lane.getEndIntersection()->isImplicitIntersection()){ result.append(" i"); continue; } bool can_go = true; for (LaneLink *laneLink : lane.getLaneLinks()) { if (!laneLink->isAvailable()) { can_go = false; break; } } result.append(can_go ? " g" : " r"); } result.append(","); } logOut << result << std::endl; } void Engine::updateLeaderAndGap() { startBarrier.wait(); endBarrier.wait(); } void Engine::notifyCross() { startBarrier.wait(); endBarrier.wait(); } void Engine::nextStep() { for (auto &flow : flows) flow.nextStep(interval); planRoute(); handleWaiting(); if (laneChange) { initSegments(); planLaneChange(); updateLeaderAndGap(); } notifyCross(); getAction(); updateLocation(); updateAction(); updateLeaderAndGap(); if (!rlTrafficLight) { std::vector &intersections = roadnet.getIntersections(); for (auto &intersection : intersections) intersection.getTrafficLight().passTime(interval); } if (saveReplay) { updateLog(); } step += 1; } void Engine::initSegments() { startBarrier.wait(); endBarrier.wait(); } bool Engine::checkPriority(int priority) { return vehiclePool.find(priority) != vehiclePool.end(); } void Engine::pushVehicle(Vehicle *const vehicle, bool pushToDrivable) { size_t threadIndex = rnd() % threadNum; vehiclePool.emplace(vehicle->getPriority(), std::make_pair(vehicle, threadIndex)); vehicleMap.emplace(vehicle->getId(), vehicle); threadVehiclePool[threadIndex].insert(vehicle); if (pushToDrivable) ((Lane *) vehicle->getCurDrivable())->pushWaitingVehicle(vehicle); } size_t Engine::getVehicleCount() const { return activeVehicleCount; } std::vector Engine::getVehicles(bool includeWaiting) const { std::vector ret; ret.reserve(activeVehicleCount); for (const Vehicle* vehicle : getRunningVehicles(includeWaiting)) { ret.emplace_back(vehicle->getId()); } return ret; } std::map Engine::getLaneVehicleCount() const { std::map ret; for (const Lane *lane : roadnet.getLanes()) { ret.emplace(lane->getId(), lane->getVehicleCount()); } return ret; } std::map Engine::getLaneWaitingVehicleCount() const { std::map ret; for (const Lane *lane : roadnet.getLanes()) { int cnt = 0; for (Vehicle *vehicle : lane->getVehicles()) { if (vehicle->getSpeed() < 0.1) { //TODO: better waiting critera cnt += 1; } } ret.emplace(lane->getId(), cnt); } return ret; } std::map> Engine::getLaneVehicles() { std::map> ret; for (const Lane *lane : roadnet.getLanes()) { std::vector vehicles; for (Vehicle *vehicle : lane->getVehicles()) { vehicles.push_back(vehicle->getId()); } ret.emplace(lane->getId(), vehicles); } return ret; } std::map Engine::getVehicleSpeed() const { std::map ret; for (const Vehicle* vehicle : getRunningVehicles()) { ret.emplace(vehicle->getId(), vehicle->getSpeed()); } return ret; } std::map Engine::getVehicleDistance() const { std::map ret; for (const Vehicle* vehicle : getRunningVehicles()) { ret.emplace(vehicle->getId(), vehicle->getDistance()); } return ret; } double Engine::getCurrentTime() const { return step * interval; } double Engine::getAverageTravelTime() const { double tt = cumulativeTravelTime; int n = finishedVehicleCnt; for (auto &vehicle_pair : vehiclePool) { auto &vehicle = vehicle_pair.second.first; tt += getCurrentTime() - vehicle->getEnterTime(); n++; } return n == 0 ? 0 : tt / n; } void Engine::pushVehicle(const std::map &info, const std::vector &roads) { VehicleInfo vehicleInfo; std::map::const_iterator it; if ((it = info.find("speed")) != info.end()) vehicleInfo.speed = it->second; if ((it = info.find("length")) != info.end()) vehicleInfo.len = it->second; if ((it = info.find("width")) != info.end()) vehicleInfo.width = it->second; if ((it = info.find("maxPosAcc")) != info.end()) vehicleInfo.maxPosAcc = it->second; if ((it = info.find("maxNegAcc")) != info.end()) vehicleInfo.maxNegAcc = it->second; if ((it = info.find("usualPosAcc")) != info.end()) vehicleInfo.usualPosAcc = it->second; if ((it = info.find("usualNegAcc")) != info.end()) vehicleInfo.usualNegAcc = it->second; if ((it = info.find("minGap")) != info.end()) vehicleInfo.minGap = it->second; if ((it = info.find("maxSpeed")) != info.end()) vehicleInfo.maxSpeed = it->second; if ((it = info.find("headwayTime")) != info.end()) vehicleInfo.headwayTime = it->second; std::vector routes; routes.reserve(roads.size()); for (auto &road: roads) routes.emplace_back(roadnet.getRoadById(road)); auto route = std::make_shared(routes); vehicleInfo.route = route; Vehicle *vehicle = new Vehicle(vehicleInfo, "manually_pushed_" + std::to_string(manuallyPushCnt++), this); pushVehicle(vehicle, false); vehicle->getFirstRoad()->addPlanRouteVehicle(vehicle); } void Engine::setTrafficLightPhase(const std::string &id, int phaseIndex) { if (!rlTrafficLight) { std::cerr << "please set rlTrafficLight to true to enable traffic light control" << std::endl; return; } roadnet.getIntersectionById(id)->getTrafficLight().setPhase(phaseIndex); } void Engine::setReplayLogFile(const std::string &logFile) { if (!saveReplayInConfig) { std::cerr << "saveReplay is not set to true in config file!" << std::endl; return; } if (logOut.is_open()) logOut.close(); logOut.open(dir + logFile); } void Engine::setSaveReplay(bool open) { if (!saveReplayInConfig) { std::cerr << "saveReplay is not set to true in config file!" << std::endl; return; } saveReplay = open; } void Engine::reset(bool resetRnd) { for (auto &vehiclePair : vehiclePool) delete vehiclePair.second.first; for (auto &pool : threadVehiclePool) pool.clear(); vehiclePool.clear(); vehicleMap.clear(); roadnet.reset(); finishedVehicleCnt = 0; cumulativeTravelTime = 0; for (auto &flow : flows) flow.reset(); step = 0; activeVehicleCount = 0; if (resetRnd) { rnd.seed(seed); } } Engine::~Engine() { logOut.close(); finished = true; for (int i = 0; i < (laneChange ? 9 : 6); ++i) { startBarrier.wait(); endBarrier.wait(); } for (auto &thread : threadPool) thread.join(); for (auto &vehiclePair : vehiclePool) delete vehiclePair.second.first; } void Engine::setLogFile(const std::string &jsonFile, const std::string &logFile) { if (!writeJsonToFile(jsonFile, jsonRoot)) { std::cerr << "write roadnet log file error" << std::endl; } logOut.open(logFile); } std::vector Engine::getRunningVehicles(bool includeWaiting) const { std::vector ret; ret.reserve(activeVehicleCount); for (const auto &vehiclePair: vehiclePool) { const Vehicle *vehicle = vehiclePair.second.first; if (vehicle->isReal() && (includeWaiting || vehicle->isRunning())) { ret.emplace_back(vehicle); } } return ret; } void Engine::scheduleLaneChange() { std::sort(laneChangeNotifyBuffer.begin(), laneChangeNotifyBuffer.end(), [](Vehicle *a, Vehicle *b){return a->laneChangeUrgency() > b->laneChangeUrgency();}); for (auto v : laneChangeNotifyBuffer){ v->updateLaneChangeNeighbor(); v->sendSignal(); // Lane Change // Insert a shadow vehicle if (v->planLaneChange() && v->canChange() && !v->isChanging()) { std::shared_ptr lc = v->getLaneChange(); if (lc->isGapValid() && v->getCurDrivable()->isLane()) { // std::cerr << getCurrentTime() <<" " << v->getId() << " dis: "<< v->getDistance() <<" Can Change from " // << ((Lane*)v->getCurDrivable())->getId()<< " to " << lc->getTarget()->getId() << std::endl; insertShadow(v); } } } laneChangeNotifyBuffer.clear(); } void Engine::insertShadow(Vehicle *vehicle) { size_t threadIndex = vehiclePool.at(vehicle->getPriority()).second; Vehicle *shadow = new Vehicle(*vehicle, vehicle->getId() + "_shadow", this); vehicleMap.emplace(shadow->getId(), shadow); vehiclePool.emplace(shadow->getPriority(), std::make_pair(shadow, threadIndex)); threadVehiclePool[threadIndex].insert(shadow); vehicle->insertShadow(shadow); activeVehicleCount++; } void Engine::loadFromFile(const char *fileName) { Archive archive(*this, fileName); archive.resume(*this); } void Engine::setVehicleSpeed(const std::string &id, double speed) { auto iter = vehicleMap.find(id); if (iter == vehicleMap.end()) { throw std::runtime_error("Vehicle '" + id + "' not found"); }else { iter->second->setCustomSpeed(speed); } } std::string Engine::getLeader(const std::string &vehicleId) const { auto iter = vehicleMap.find(vehicleId); if (iter == vehicleMap.end()) { throw std::runtime_error("Vehicle '" + vehicleId + "' not found"); }else { Vehicle *vehicle = iter->second; if (laneChange) { if (!vehicle->isReal()) vehicle = vehicle->getPartner(); } Vehicle *leader = vehicle->getLeader(); if (leader) return leader->getId(); else return ""; } } bool Engine::setRoute(const std::string &vehicle_id, const std::vector &anchor_id) { auto vehicle_itr = vehicleMap.find(vehicle_id); if (vehicle_itr == vehicleMap.end()) return false; Vehicle *vehicle = vehicle_itr->second; std::vector anchors; for (const auto &id : anchor_id) { auto anchor = roadnet.getRoadById(id); if (!anchor) return false; anchors.emplace_back(anchor); } return vehicle->setRoute(anchors); } std::map Engine::getVehicleInfo(const std::string &id) const { auto iter = vehicleMap.find(id); if (iter == vehicleMap.end()) { throw std::runtime_error("Vehicle '" + id + "' not found"); }else { Vehicle *vehicle = iter->second; return vehicle->getInfo(); } } }