#include "vehicle/vehicle.h" #include "engine/engine.h" #include #include #include namespace CityFlow { Vehicle::ControllerInfo::ControllerInfo(Vehicle *vehicle, std::shared_ptr route, std::mt19937 *rnd) : router(vehicle, route, rnd) { enterLaneLinkTime = std::numeric_limits::max(); } Vehicle::ControllerInfo::ControllerInfo(Vehicle *vehicle, const Vehicle::ControllerInfo &other): ControllerInfo(other) { router.setVehicle(vehicle); } Vehicle::Vehicle(const Vehicle &vehicle, Flow *flow) : vehicleInfo(vehicle.vehicleInfo), controllerInfo(this, vehicle.controllerInfo), laneChangeInfo(vehicle.laneChangeInfo), buffer(vehicle.buffer), priority(vehicle.priority), id(vehicle.id), engine(vehicle.engine), laneChange(std::make_shared(this, *vehicle.laneChange)), flow(flow){ enterTime = vehicle.enterTime; } Vehicle::Vehicle(const Vehicle &vehicle, const std::string &id, Engine *engine, Flow *flow) : vehicleInfo(vehicle.vehicleInfo), controllerInfo(this, vehicle.controllerInfo), laneChangeInfo(vehicle.laneChangeInfo), buffer(vehicle.buffer), id(id), engine(engine), laneChange(std::make_shared(this)), flow(flow){ while (engine->checkPriority(priority = engine->rnd())); controllerInfo.router.setVehicle(this); enterTime = vehicle.enterTime; } Vehicle::Vehicle(const VehicleInfo &vehicleInfo, const std::string &id, Engine *engine, Flow *flow) : vehicleInfo(vehicleInfo), controllerInfo(this, vehicleInfo.route, &(engine->rnd)), id(id), engine(engine), laneChange(std::make_shared(this)), flow(flow){ controllerInfo.approachingIntersectionDistance = vehicleInfo.maxSpeed * vehicleInfo.maxSpeed / vehicleInfo.usualNegAcc / 2 + vehicleInfo.maxSpeed * engine->getInterval() * 2; while (engine->checkPriority(priority = engine->rnd())); enterTime = engine->getCurrentTime(); } void Vehicle::setDeltaDistance(double dis) { if (!buffer.isDisSet || dis < buffer.deltaDis) { unSetEnd(); unSetDrivable(); buffer.deltaDis = dis; dis = dis + controllerInfo.dis; Drivable *drivable = getCurDrivable(); for (int i = 0; drivable && dis > drivable->getLength(); ++i) { dis -= drivable->getLength(); Drivable *nextDrivable = controllerInfo.router.getNextDrivable(i); if (nextDrivable == nullptr) { assert(controllerInfo.router.isLastRoad(drivable)); setEnd(true); } drivable = nextDrivable; setDrivable(drivable); } setDis(dis); } } void Vehicle::setSpeed(double speed) { buffer.speed = speed; buffer.isSpeedSet = true; } Drivable *Vehicle::getChangedDrivable() const { if (!buffer.isDrivableSet) return nullptr; return buffer.drivable; } Point Vehicle::getPoint() const { if (fabs(laneChangeInfo.offset) < eps || !controllerInfo.drivable->isLane()) { return controllerInfo.drivable->getPointByDistance(controllerInfo.dis); } else { assert(controllerInfo.drivable->isLane()); const Lane *lane = static_cast(controllerInfo.drivable); Point origin = lane->getPointByDistance(controllerInfo.dis); Point next; double percentage; std::vector &lans = lane->getBelongRoad()->getLanes(); if (laneChangeInfo.offset > 0) { next = lans[lane->getLaneIndex() + 1].getPointByDistance(controllerInfo.dis); percentage = 2 * laneChangeInfo.offset / (lane->getWidth() + lans[lane->getLaneIndex() + 1].getWidth()); } else { next = lans[lane->getLaneIndex() - 1].getPointByDistance(controllerInfo.dis); percentage = -2 * laneChangeInfo.offset / (lane->getWidth() + lans[lane->getLaneIndex() - 1].getWidth()); } Point cur; cur.x = next.x * percentage + origin.x * (1 - percentage); cur.y = next.y * percentage + origin.y * (1 - percentage); return cur; } } void Vehicle::update() { // TODO: use something like reflection? if (buffer.isEndSet) { controllerInfo.end = buffer.end; buffer.isEndSet = false; } if (buffer.isDisSet) { controllerInfo.dis = buffer.dis; buffer.isDisSet = false; } if (buffer.isSpeedSet) { vehicleInfo.speed = buffer.speed; buffer.isSpeedSet = false; } if (buffer.isCustomSpeedSet) { buffer.isCustomSpeedSet = false; } if (buffer.isDrivableSet) { controllerInfo.prevDrivable = controllerInfo.drivable; controllerInfo.drivable = buffer.drivable; buffer.isDrivableSet = false; controllerInfo.router.update(); } if (buffer.isEnterLaneLinkTimeSet) { controllerInfo.enterLaneLinkTime = buffer.enterLaneLinkTime; buffer.isEnterLaneLinkTimeSet = false; } if (buffer.isBlockerSet) { controllerInfo.blocker = buffer.blocker; buffer.isBlockerSet = false; } else { controllerInfo.blocker = nullptr; } if (buffer.isNotifiedVehicles) { buffer.notifiedVehicles.clear(); buffer.isNotifiedVehicles = false; } } std::pair Vehicle::getCurPos() const { std::pair ret; ret.first = controllerInfo.drivable->getPointByDistance(controllerInfo.dis); Point direction = controllerInfo.drivable->getDirectionByDistance(controllerInfo.dis); Point tail(ret.first); tail.x -= direction.x * vehicleInfo.len; tail.y -= direction.y * vehicleInfo.len; ret.second = tail; return ret; } void Vehicle::updateLeaderAndGap(Vehicle *leader) { if (leader != nullptr && leader->getCurDrivable() == getCurDrivable()) { controllerInfo.leader = leader; controllerInfo.gap = leader->getDistance() - leader->getLen() - controllerInfo.dis; } else { controllerInfo.leader = nullptr; Drivable *drivable = nullptr; Vehicle *candidateLeader = nullptr; double candidateGap = 0; double dis = controllerInfo.drivable->getLength() - controllerInfo.dis; for (int i = 0; ; ++i) { drivable = getNextDrivable(i); if (drivable == nullptr) return; if (drivable->isLaneLink()) { // if laneLink, check all laneLink start from previous lane, because lanelinks may overlap for (auto laneLink : static_cast(drivable)->getStartLane()->getLaneLinks()) { if ((candidateLeader = laneLink->getLastVehicle()) != nullptr) { candidateGap = dis + candidateLeader->getDistance() - candidateLeader->getLen(); if (controllerInfo.leader == nullptr || candidateGap < controllerInfo.gap) { controllerInfo.leader = candidateLeader; controllerInfo.gap = candidateGap; } } } if (controllerInfo.leader) return; } else { if ((controllerInfo.leader = drivable->getLastVehicle()) != nullptr) { controllerInfo.gap = dis + controllerInfo.leader->getDistance() - controllerInfo.leader->getLen(); return; } } dis += drivable->getLength(); if (dis > vehicleInfo.maxSpeed * vehicleInfo.maxSpeed / vehicleInfo.usualNegAcc / 2 + vehicleInfo.maxSpeed * engine->getInterval() * 2) return; } return; } } double Vehicle::getNoCollisionSpeed(double vL, double dL, double vF, double dF, double gap, double interval, double targetGap) const { double c = vF * interval / 2 + targetGap - 0.5 * vL * vL / dL - gap; double a = 0.5 / dF; double b = 0.5 * interval; if (b * b < 4 * a * c) return -100; double v1 = 0.5 / a * (sqrt(b * b - 4 * a * c) - b); double v2 = 2 * vL - dL * interval + 2 * (gap - targetGap) / interval; return min2double(v1, v2); } // should be move to seperate CarFollowing (Controller?) class later? double Vehicle::getCarFollowSpeed(double interval) { Vehicle *leader = getLeader(); if (leader == nullptr) return hasSetCustomSpeed() ? buffer.customSpeed : vehicleInfo.maxSpeed; // collision free double v = getNoCollisionSpeed(leader->getSpeed(), leader->getMaxNegAcc(), vehicleInfo.speed, vehicleInfo.maxNegAcc, controllerInfo.gap, interval, 0); if (hasSetCustomSpeed()) return min2double(buffer.customSpeed, v); // safe distance // get relative decel (mimic real scenario) double assumeDecel = 0, leaderSpeed = leader->getSpeed(); if (vehicleInfo.speed > leaderSpeed) { assumeDecel = vehicleInfo.speed - leaderSpeed; } v = min2double(v, getNoCollisionSpeed(leader->getSpeed(), leader->getUsualNegAcc(), vehicleInfo.speed, vehicleInfo.usualNegAcc, controllerInfo.gap, interval, vehicleInfo.minGap )); v = min2double(v, (controllerInfo.gap + (leaderSpeed + assumeDecel / 2) * interval - vehicleInfo.speed * interval / 2) / (vehicleInfo.headwayTime + interval / 2)); return v; } double Vehicle::getStopBeforeSpeed(double distance, double interval) const { assert(distance >= 0); if (getBrakeDistanceAfterAccel(vehicleInfo.usualPosAcc, vehicleInfo.usualNegAcc, interval) < distance) return vehicleInfo.speed + vehicleInfo.usualPosAcc * interval; double takeInterval = 2 * distance / (vehicleInfo.speed + eps) / interval; if (takeInterval >= 1) { return vehicleInfo.speed - vehicleInfo.speed / (int) takeInterval; } else { return vehicleInfo.speed - vehicleInfo.speed / takeInterval; } } int Vehicle::getReachSteps(double distance, double targetSpeed, double acc) const { if (distance <= 0) { return 0; } if (vehicleInfo.speed > targetSpeed) { return std::ceil(distance / vehicleInfo.speed); } double distanceUntilTargetSpeed = getDistanceUntilSpeed(targetSpeed, acc); double interval = engine->getInterval(); if (distanceUntilTargetSpeed > distance) { return std::ceil((std::sqrt( vehicleInfo.speed * vehicleInfo.speed + 2 * acc * distance) - vehicleInfo.speed) / acc / interval); } else { return std::ceil((targetSpeed - vehicleInfo.speed) / acc / interval) + std::ceil( (distance - distanceUntilTargetSpeed) / targetSpeed / interval); } } int Vehicle::getReachStepsOnLaneLink(double distance, LaneLink *laneLink) const { return getReachSteps(distance, laneLink->isTurn() ? vehicleInfo.turnSpeed : vehicleInfo.maxSpeed, vehicleInfo.usualPosAcc); } double Vehicle::getDistanceUntilSpeed(double speed, double acc) const { if (speed <= vehicleInfo.speed) return 0; double interval = engine->getInterval(); int stage1steps = std::floor((speed - vehicleInfo.speed) / acc / interval); double stage1speed = vehicleInfo.speed + stage1steps * acc / interval; double stage1dis = (vehicleInfo.speed + stage1speed) * (stage1steps * interval) / 2; return stage1dis + (stage1speed < speed ? ((stage1speed + speed) * interval / 2) : 0); } bool Vehicle::canYield(double dist) const { return (dist > 0 && getMinBrakeDistance() < dist - vehicleInfo.yieldDistance) || (dist < 0 && dist + vehicleInfo.len < 0); } bool Vehicle::isIntersectionRelated() { if (controllerInfo.drivable->isLaneLink()) return true; if (controllerInfo.drivable->isLane()) { Drivable *drivable = getNextDrivable(); if (drivable && drivable->isLaneLink() && controllerInfo.drivable->getLength() - controllerInfo.dis <= controllerInfo.approachingIntersectionDistance) { return true; } } return false; } double Vehicle::getBrakeDistanceAfterAccel(double acc, double dec, double interval) const { double currentSpeed = vehicleInfo.speed; double nextSpeed = currentSpeed + acc * interval; return (currentSpeed + nextSpeed) * interval / 2 + (nextSpeed * nextSpeed / dec / 2); } ControlInfo Vehicle::getNextSpeed(double interval) { // TODO: pass as parameter or not? ControlInfo controlInfo; Drivable *drivable = controllerInfo.drivable; double v = vehicleInfo.maxSpeed; v = min2double(v, vehicleInfo.speed + vehicleInfo.maxPosAcc * interval); // TODO: random??? v = min2double(v, drivable->getMaxSpeed()); // car follow v = min2double(v, getCarFollowSpeed(interval)); if (isIntersectionRelated()) { v = min2double(v, getIntersectionRelatedSpeed(interval)); } if (laneChange){ v = min2double(v, laneChange->yieldSpeed(interval)); if (!controllerInfo.router.onValidLane()) { double vn = getNoCollisionSpeed(0,1,getSpeed(), getMaxNegAcc(), getCurDrivable()->getLength() - getDistance(), interval, getMinGap()); v = min2double(v, vn); } } v = max2double(v, vehicleInfo.speed - vehicleInfo.maxNegAcc * interval); controlInfo.speed = v; return controlInfo; } double Vehicle::getIntersectionRelatedSpeed(double interval) { double v = vehicleInfo.maxSpeed; Drivable *nextDrivable = getNextDrivable(); const LaneLink *laneLink = nullptr; if (nextDrivable && nextDrivable->isLaneLink()) { laneLink = (LaneLink *) nextDrivable; if (!laneLink->isAvailable() || !laneLink->getEndLane()->canEnter( this)) { // not only the first vehicle should follow intersection logic if (getMinBrakeDistance() > controllerInfo.drivable->getLength() - controllerInfo.dis) { // TODO: what if it cannot brake before red light? } else { v = min2double(v, getStopBeforeSpeed(controllerInfo.drivable->getLength() - controllerInfo.dis, interval)); return v; } } if (laneLink->isTurn()) { v = min2double(v, vehicleInfo.turnSpeed); // TODO: define turn speed } } if (laneLink == nullptr && controllerInfo.drivable->isLaneLink()) laneLink = static_cast(controllerInfo.drivable); double distanceToLaneLinkStart = controllerInfo.drivable->isLane() ? -(controllerInfo.drivable->getLength() - controllerInfo.dis) : controllerInfo.dis; double distanceOnLaneLink; for (auto &cross : laneLink->getCrosses()) { distanceOnLaneLink = cross->getDistanceByLane(laneLink); if (distanceOnLaneLink < distanceToLaneLinkStart) continue; if (!cross->canPass(this, laneLink, distanceToLaneLinkStart)) { v = min2double(v, getStopBeforeSpeed( distanceOnLaneLink - distanceToLaneLinkStart - vehicleInfo.yieldDistance, interval)); // TODO: headway distance setBlocker(cross->getFoeVehicle(laneLink)); break; } } return v; } void Vehicle::finishChanging() { laneChange->finishChanging(); setEnd(true); } void Vehicle::setLane(Lane *nextLane) { controllerInfo.drivable = nextLane; } Drivable *Vehicle::getCurDrivable() const { return controllerInfo.drivable; } void Vehicle::receiveSignal(Vehicle *sender) { if (laneChange->changing) return; auto signal_recv = laneChange->signalRecv; auto signal_send = laneChange->signalSend; int curPriority = signal_recv ? signal_recv->source->getPriority() : -1; int newPriority = sender->getPriority(); if ((!signal_recv || curPriority < newPriority) && (!signal_send || priority < newPriority) ) laneChange->signalRecv = sender->laneChange->signalSend; } std::list::iterator Vehicle::getListIterator() { assert(getCurDrivable()->isLane()); Segment *seg = ((Lane *)getCurDrivable())->getSegment(getSegmentIndex()); auto result = seg->findVehicle(this); return result; } void Vehicle::abortLaneChange() { assert(laneChangeInfo.partner); this->setEnd(true); laneChange->abortChanging(); } Road *Vehicle::getFirstRoad() { return controllerInfo.router.getFirstRoad(); } void Vehicle::setFirstDrivable() { controllerInfo.drivable = controllerInfo.router.getFirstDrivable(); } void Vehicle::updateRoute() { routeValid = controllerInfo.router.updateShortestPath(); } bool Vehicle::setRoute(const std::vector &anchor) { return controllerInfo.router.setRoute(anchor); } std::map Vehicle::getInfo() const{ std::map info; info["running"] = std::to_string(isRunning()); if (!isRunning()) return info; info["distance"] = std::to_string(getDistance()); info["speed"] = std::to_string(getSpeed()); const auto &drivable = getCurDrivable(); info["drivable"] = drivable->getId(); const auto &road = drivable->isLane() ? getCurLane()->getBelongRoad() : nullptr; if (road) { info["road"] = road->getId(); info["intersection"] = road->getEndIntersection().getId(); } // add routing info std::string route; for (const auto &r : controllerInfo.router.getFollowingRoads()) { route += r->getId() + " "; } info["route"] = route; return info; } }