void MELoop::teleportVehicle(MEVehicle* veh, MESegment* const toSegment) { const SUMOTime leaveTime = veh->getEventTime(); MESegment* const onSegment = veh->getSegment(); const bool teleporting = (onSegment == 0); // is the vehicle already teleporting? // try to find a place on the current edge MESegment* teleSegment = toSegment->getNextSegment(); while (teleSegment != 0 && !teleSegment->hasSpaceFor(veh, leaveTime)) { // @caution the time to get to the next segment here is ignored XXX teleSegment = teleSegment->getNextSegment(); } if (teleSegment != 0) { if (!teleporting) { // we managed to teleport in a single jump WRITE_WARNING("Teleporting vehicle '" + veh->getID() + "'; waited too long, from edge '" + onSegment->getEdge().getID() + "':" + toString(onSegment->getIndex()) + " to edge '" + teleSegment->getEdge().getID() + "':" + toString(teleSegment->getIndex()) + ", time " + time2string(leaveTime) + "."); MSNet::getInstance()->getVehicleControl().registerTeleportJam(); } changeSegment(veh, leaveTime, teleSegment, true); teleSegment->setEntryBlockTime(leaveTime); // teleports should not block normal flow } else { // teleport across the current edge and try insertion later if (!teleporting) { // announce start of multi-step teleport, arrival will be announced in changeSegment() WRITE_WARNING("Teleporting vehicle '" + veh->getID() + "'; waited too long, from edge '" + onSegment->getEdge().getID() + "':" + toString(onSegment->getIndex()) + ", time " + time2string(leaveTime) + "."); MSNet::getInstance()->getVehicleControl().registerTeleportJam(); // remove from current segment onSegment->send(veh, 0, leaveTime); // mark veh as teleporting veh->setSegment(0, 0); } // @caution microsim uses current travel time teleport duration const SUMOTime teleArrival = leaveTime + TIME2STEPS(veh->getEdge()->getLength() / veh->getEdge()->getSpeedLimit()); const bool atDest = veh->moveRoutePointer(); if (atDest) { // teleporting to end of route changeSegment(veh, teleArrival, 0, true); } else { veh->setEventTime(teleArrival); addLeaderCar(veh, 0); // teleporting vehicles must react to rerouters getSegmentForEdge(*veh->getEdge())->addReminders(veh); veh->activateReminders(MSMoveReminder::NOTIFICATION_JUNCTION); } } }
bool MSEdge::insertVehicle(SUMOVehicle& v, SUMOTime time, const bool checkOnly) const { // when vaporizing, no vehicles are inserted, but checking needs to be successful to trigger removal if (isVaporizing()) { return checkOnly; } const SUMOVehicleParameter& pars = v.getParameter(); const MSVehicleType& type = v.getVehicleType(); if (pars.departSpeedProcedure == DEPART_SPEED_GIVEN && pars.departSpeed > getVehicleMaxSpeed(&v)) { if (type.getSpeedDeviation() > 0 && pars.departSpeed <= type.getSpeedFactor() * getSpeedLimit() * (2 * type.getSpeedDeviation() + 1.)) { WRITE_WARNING("Choosing new speed factor for vehicle '" + pars.id + "' to match departure speed."); v.setChosenSpeedFactor(type.computeChosenSpeedDeviation(0, pars.departSpeed / (type.getSpeedFactor() * getSpeedLimit()))); } else { throw ProcessError("Departure speed for vehicle '" + pars.id + "' is too high for the departure edge '" + getID() + "'."); } } if (checkOnly && v.getEdge()->getPurpose() == MSEdge::EDGEFUNCTION_DISTRICT) { return true; } if (!checkOnly) { std::string msg; if (!v.hasValidRoute(msg)) { if (MSGlobals::gCheckRoutes) { throw ProcessError("Vehicle '" + v.getID() + "' has no valid route. " + msg); } else if (v.getEdge()->getPurpose() == MSEdge::EDGEFUNCTION_DISTRICT) { WRITE_WARNING("Removing vehicle '" + pars.id + "' which has no valid route."); MSNet::getInstance()->getInsertionControl().descheduleDeparture(&v); return false; } } } if (MSGlobals::gUseMesoSim) { SUMOReal pos = 0.0; switch (pars.departPosProcedure) { case DEPART_POS_GIVEN: if (pars.departPos >= 0.) { pos = pars.departPos; } else { pos = pars.departPos + getLength(); } if (pos < 0 || pos > getLength()) { WRITE_WARNING("Invalid departPos " + toString(pos) + " given for vehicle '" + v.getID() + "'. Inserting at lane end instead."); pos = getLength(); } break; case DEPART_POS_RANDOM: case DEPART_POS_RANDOM_FREE: pos = RandHelper::rand(getLength()); break; default: break; } bool result = false; MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this, pos); MEVehicle* veh = static_cast<MEVehicle*>(&v); if (pars.departPosProcedure == DEPART_POS_FREE) { while (segment != 0 && !result) { if (checkOnly) { result = segment->hasSpaceFor(veh, time, true); } else { result = segment->initialise(veh, time); } segment = segment->getNextSegment(); } } else { if (checkOnly) { result = segment->hasSpaceFor(veh, time, true); } else { result = segment->initialise(veh, time); } } return result; } if (checkOnly) { switch (v.getParameter().departLaneProcedure) { case DEPART_LANE_GIVEN: case DEPART_LANE_DEFAULT: case DEPART_LANE_FIRST_ALLOWED: { const SUMOReal occupancy = getDepartLane(static_cast<MSVehicle&>(v))->getBruttoOccupancy(); return occupancy == (SUMOReal)0 || occupancy * myLength + v.getVehicleType().getLengthWithGap() <= myLength; } default: for (std::vector<MSLane*>::const_iterator i = myLanes->begin(); i != myLanes->end(); ++i) { const SUMOReal occupancy = (*i)->getBruttoOccupancy(); if (occupancy == (SUMOReal)0 || occupancy * myLength + v.getVehicleType().getLengthWithGap() <= myLength) { return true; } } } return false; } MSLane* insertionLane = getDepartLane(static_cast<MSVehicle&>(v)); return insertionLane != 0 && insertionLane->insertVehicle(static_cast<MSVehicle&>(v)); }