예제 #1
0
// ===========================================================================
// method definitions
// ===========================================================================
GUILaneWrapper::GUILaneWrapper(GUIGlObjectStorage &idStorage,
                               MSLane &lane, const Position2DVector &shape) throw()
        : GUIGlObject(idStorage, "lane:"+lane.getID()),
        myLane(lane), myShape(shape) {
    SUMOReal x1 = shape[0].x();
    SUMOReal y1 = shape[0].y();
    SUMOReal x2 = shape[-1].x();
    SUMOReal y2 = shape[-1].y();
    SUMOReal length = myLane.getLength();
    // also the virtual length is set in here
    myVisLength = sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));
    // check maximum speed
    if (myAllMaxSpeed<lane.getMaxSpeed()) {
        myAllMaxSpeed = lane.getMaxSpeed();
    }
    //
    myShapeRotations.reserve(myShape.size()-1);
    myShapeLengths.reserve(myShape.size()-1);
    int e = (int) myShape.size() - 1;
    for (int i=0; i<e; ++i) {
        const Position2D &f = myShape[i];
        const Position2D &s = myShape[i+1];
        myShapeLengths.push_back(f.distanceTo(s));
        myShapeRotations.push_back((SUMOReal) atan2((s.x()-f.x()), (f.y()-s.y()))*(SUMOReal) 180.0/(SUMOReal) PI);
    }
}
예제 #2
0
void
MSFullExport::writeLane(OutputDevice& of, const MSLane& lane) {

    of.openTag("lane").writeAttr("id", lane.getID()).writeAttr("CO", lane.getCOEmissions()).writeAttr("CO2", lane.getCO2Emissions());
    of.writeAttr("NOx", lane.getNOxEmissions()).writeAttr("PMx", lane.getPMxEmissions()).writeAttr("HC", lane.getHCEmissions());
    of.writeAttr("noise", lane.getHarmonoise_NoiseEmissions()).writeAttr("fuel", lane.getFuelConsumption()).writeAttr("maxspeed", lane.getSpeedLimit());
    of.writeAttr("meanspeed", lane.getMeanSpeed() * 3.6).writeAttr("occupancy", lane.getNettoOccupancy()).writeAttr("vehicle_count", lane.getVehicleNumber());
    of.closeTag();
}
예제 #3
0
// ===========================================================================
// method definitions
// ===========================================================================
MSCalibrator::MSCalibrator(const std::string& id,
                           const MSEdge* const edge,
                           MSLane* lane,
                           const double pos,
                           const std::string& aXMLFilename,
                           const std::string& outputFilename,
                           const SUMOTime freq, const double length,
                           const MSRouteProbe* probe,
                           bool addLaneMeanData) :
    MSTrigger(id),
    MSRouteHandler(aXMLFilename, true),
    myEdge(edge),
    myLane(lane),
    myPos(pos), myProbe(probe),
    myEdgeMeanData(nullptr, length, false, nullptr),
    myCurrentStateInterval(myIntervals.begin()),
    myOutput(nullptr), myFrequency(freq), myRemoved(0),
    myInserted(0), myClearedInJam(0),
    mySpeedIsDefault(true), myDidSpeedAdaption(false), myDidInit(false),
    myDefaultSpeed(myLane == nullptr ? myEdge->getSpeedLimit() : myLane->getSpeedLimit()),
    myHaveWarnedAboutClearingJam(false),
    myAmActive(false) {
    if (outputFilename != "") {
        myOutput = &OutputDevice::getDevice(outputFilename);
        myOutput->writeXMLHeader("calibratorstats", "calibratorstats_file.xsd");
    }
    if (aXMLFilename != "") {
        XMLSubSys::runParser(*this, aXMLFilename);
        if (!myDidInit) {
            init();
        }
    }
    if (addLaneMeanData) {
        // disabled for METriggeredCalibrator
        for (int i = 0; i < (int)myEdge->getLanes().size(); ++i) {
            MSLane* lane = myEdge->getLanes()[i];
            if (myLane == nullptr || myLane == lane) {
                //std::cout << " cali=" << getID() << " myLane=" << Named::getIDSecure(myLane) << " checkLane=" << i << "\n";
                MSMeanData_Net::MSLaneMeanDataValues* laneData = new MSMeanData_Net::MSLaneMeanDataValues(lane, lane->getLength(), true, nullptr);
                laneData->setDescription("meandata_calibrator_" + lane->getID());
                LeftoverReminders.push_back(laneData);
                myLaneMeanData.push_back(laneData);
                VehicleRemover* remover = new VehicleRemover(lane, (int)i, this);
                LeftoverReminders.push_back(remover);
                myVehicleRemovers.push_back(remover);
            }
        }
    }
}
void
MSFullExport::writeLane(OutputDevice& of, const MSLane& lane) {

    of.openTag("lane")
            << " id=\"" << lane.getID()
            << "\" co=\"" << lane.getHBEFA_COEmissions()
            << "\" co2=\"" << lane.getHBEFA_CO2Emissions()
            << "\" nox=\"" << lane.getHBEFA_NOxEmissions()
            << "\" pmx=\"" << lane.getHBEFA_PMxEmissions()
            << "\" hc=\"" << lane.getHBEFA_HCEmissions()
            << "\" noise=\"" << lane.getHarmonoise_NoiseEmissions()
            << "\" fuel=\"" << lane.getHBEFA_FuelConsumption()
            << "\" maxspeed=\"" << lane.getSpeedLimit() * 3.6
            << "\" meanspeed=\"" << lane.getMeanSpeed() * 3.6
            << "\" occupancy=\"" << lane.getOccupancy()
            << "\" vehicle_count=\"" << lane.getVehicleNumber() << "\"";

    of.closeTag();

}
예제 #5
0
void
MSActuatedTrafficLightLogic::init(NLDetectorBuilder& nb) {
    MSTrafficLightLogic::init(nb);
    assert(myLanes.size() > 0);
    // change values for setting the loops and lanestate-detectors, here
    //SUMOTime inductLoopInterval = 1; //
    LaneVectorVector::const_iterator i2;
    LaneVector::const_iterator i;
    // build the induct loops
    double maxDetectorGap = 0;
    for (i2 = myLanes.begin(); i2 != myLanes.end(); ++i2) {
        const LaneVector& lanes = *i2;
        for (i = lanes.begin(); i != lanes.end(); i++) {
            MSLane* lane = (*i);
            if (noVehicles(lane->getPermissions())) {
                // do not build detectors on green verges or sidewalks
                continue;
            }
            double length = lane->getLength();
            double speed = lane->getSpeedLimit();
            double inductLoopPosition = myDetectorGap * speed;
            // check whether the lane is long enough
            double ilpos = length - inductLoopPosition;
            if (ilpos < 0) {
                ilpos = 0;
            }
            // Build the induct loop and set it into the container
            std::string id = "TLS" + myID + "_" + myProgramID + "_InductLoopOn_" + lane->getID();
            if (myInductLoops.find(lane) == myInductLoops.end()) {
                myInductLoops[lane] = nb.createInductLoop(id, lane, ilpos, myVehicleTypes, myShowDetectors);
                MSNet::getInstance()->getDetectorControl().add(SUMO_TAG_INDUCTION_LOOP, myInductLoops[lane], myFile, myFreq);
            }
            maxDetectorGap = MAX2(maxDetectorGap, length - ilpos);
        }
    }
    // warn if the minGap is insufficient to clear vehicles between stop line and detector
    SUMOTime minMinDur = getMinimumMinDuration();
    if (floor(floor(maxDetectorGap / DEFAULT_LENGTH_WITH_GAP) * myPassingTime) > STEPS2TIME(minMinDur)) {
        WRITE_WARNING("At actuated tlLogic '" + getID() + "', minDur " + time2string(minMinDur) + " is too short for a detector gap of " + toString(maxDetectorGap) + "m.");
    }
}
// ===========================================================================
// method definitions
// ===========================================================================
GUILaneWrapper::GUILaneWrapper(MSLane& lane, const PositionVector& shape, unsigned int index) :
    GUIGlObject(GLO_LANE, lane.getID()),
    myLane(lane),
    myShape(shape),
    myIndex(index)
#ifdef HAVE_OSG
    , myGeom(0)
#endif
{
    myShapeRotations.reserve(myShape.size() - 1);
    myShapeLengths.reserve(myShape.size() - 1);
    int e = (int) myShape.size() - 1;
    for (int i = 0; i < e; ++i) {
        const Position& f = myShape[i];
        const Position& s = myShape[i + 1];
        myShapeLengths.push_back(f.distanceTo2D(s));
        myShapeRotations.push_back(RAD2DEG(atan2(s.x() - f.x(), f.y() - s.y())));
    }
    //
    myHalfLaneWidth = (SUMOReal)(myLane.getWidth() / 2.);
    myQuarterLaneWidth = (SUMOReal)(myLane.getWidth() / 4.);
}
예제 #7
0
void
MSQueueExport::writeLane(OutputDevice& of, const MSLane& lane) {
    // maximum of all vehicle waiting times
    SUMOReal queueing_time = 0.0;
    // back of last stopped vehicle (XXX does not check for continuous queue)
    SUMOReal queueing_length = 0.0;
    // back of last slow vehicle (XXX does not check for continuous queue)
    SUMOReal queueing_length2 = 0.0;
    const SUMOReal threshold_velocity = 5 / 3.6; // slow

    if (!lane.empty()) {
        for (MSLane::VehCont::const_iterator it_veh = lane.myVehicles.begin(); it_veh != lane.myVehicles.end(); ++it_veh) {
            const MSVehicle& veh = **it_veh;
            if (!veh.isOnRoad()) {
                continue;
            }

            if (veh.getWaitingSeconds() > 0) {
                queueing_time = MAX2(veh.getWaitingSeconds(), queueing_time);
                const SUMOReal veh_back_to_lane_end = (lane.getLength() - veh.getPositionOnLane()) + veh.getVehicleType().getLength();
                queueing_length = MAX2(veh_back_to_lane_end, queueing_length);
            }

            //Experimental
            if (veh.getSpeed() < (threshold_velocity) && (veh.getPositionOnLane() > (veh.getLane()->getLength()) * 0.25)) {
                const SUMOReal veh_back_to_lane_end = (lane.getLength() - veh.getPositionOnLane()) + veh.getVehicleType().getLength();
                queueing_length2 = MAX2(veh_back_to_lane_end, queueing_length2);
            }
        }
    }

    //Output
    if (queueing_length > 1 || queueing_length2 > 1) {
        of.openTag("lane").writeAttr("id", lane.getID()).writeAttr("queueing_time", queueing_time).writeAttr("queueing_length", queueing_length);
        of.writeAttr("queueing_length_experimental", queueing_length2).closeTag();
    }
}
예제 #8
0
void
NLHandler::addConnection(const SUMOSAXAttributes& attrs) {
    bool ok = true;
    std::string fromID = attrs.get<std::string>(SUMO_ATTR_FROM, 0, ok);
    if (!MSGlobals::gUsingInternalLanes && fromID[0] == ':') {
        return;
    }

    try {
        bool ok = true;
        const std::string toID = attrs.get<std::string>(SUMO_ATTR_TO, 0, ok);
        const int fromLaneIdx = attrs.get<int>(SUMO_ATTR_FROM_LANE, 0, ok);
        const int toLaneIdx = attrs.get<int>(SUMO_ATTR_TO_LANE, 0, ok);
        LinkDirection dir = parseLinkDir(attrs.get<std::string>(SUMO_ATTR_DIR, 0, ok));
        LinkState state = parseLinkState(attrs.get<std::string>(SUMO_ATTR_STATE, 0, ok));
        std::string tlID = attrs.getOpt<std::string>(SUMO_ATTR_TLID, 0, ok, "");
#ifdef HAVE_INTERNAL_LANES
        std::string viaID = attrs.getOpt<std::string>(SUMO_ATTR_VIA, 0, ok, "");
#endif

        MSEdge* from = MSEdge::dictionary(fromID);
        if (from == 0) {
            WRITE_ERROR("Unknown from-edge '" + fromID + "' in connection");
            return;
        }
        MSEdge* to = MSEdge::dictionary(toID);
        if (to == 0) {
            WRITE_ERROR("Unknown to-edge '" + toID + "' in connection");
            return;
        }
        if (fromLaneIdx < 0 || static_cast<unsigned int>(fromLaneIdx) >= from->getLanes().size() ||
                toLaneIdx < 0 || static_cast<unsigned int>(toLaneIdx) >= to->getLanes().size()) {
            WRITE_ERROR("Invalid lane index in connection from '" + from->getID() + "' to '" + to->getID() + "'.");
            return;
        }
        MSLane* fromLane = from->getLanes()[fromLaneIdx];
        MSLane* toLane = to->getLanes()[toLaneIdx];
        assert(fromLane);
        assert(toLane);

        int tlLinkIdx = -1;
        if (tlID != "") {
            tlLinkIdx = attrs.get<int>(SUMO_ATTR_TLLINKINDEX, 0, ok);
            // make sure that the index is in range
            MSTrafficLightLogic* logic = myJunctionControlBuilder.getTLLogic(tlID).getActive();
            if (tlLinkIdx < 0 || tlLinkIdx >= (int)logic->getCurrentPhaseDef().getState().size()) {
                WRITE_ERROR("Invalid " + toString(SUMO_ATTR_TLLINKINDEX) + " '" + toString(tlLinkIdx) +
                            "' in connection controlled by '" + tlID + "'");
                return;
            }
            if (!ok) {
                return;
            }
        }
        SUMOReal length = fromLane->getShape()[-1].distanceTo(toLane->getShape()[0]);
        MSLink* link = 0;

        // build the link
#ifdef HAVE_INTERNAL_LANES
        MSLane* via = 0;
        if (viaID != "" && MSGlobals::gUsingInternalLanes) {
            via = MSLane::dictionary(viaID);
            if (via == 0) {
                WRITE_ERROR("An unknown lane ('" + viaID +
                            "') should be set as a via-lane for lane '" + toLane->getID() + "'.");
                return;
            }
            length = via->getLength();
        }
        link = new MSLink(toLane, via, dir, state, length);
        if (via != 0) {
            via->addIncomingLane(fromLane, link);
        } else {
            toLane->addIncomingLane(fromLane, link);
        }
#else
        link = new MSLink(toLane, dir, state, length);
        toLane->addIncomingLane(fromLane, link);
#endif
        toLane->addApproachingLane(fromLane);

        // if a traffic light is responsible for it, inform the traffic light
        // check whether this link is controlled by a traffic light
        if (tlID != "") {
            myJunctionControlBuilder.getTLLogic(tlID).addLink(link, fromLane, tlLinkIdx);
        }
        // add the link
        fromLane->addLink(link);

    } catch (InvalidArgument& e) {
        WRITE_ERROR(e.what());
    }
}
예제 #9
0
void
Person::moveToXY(const std::string& personID, const std::string& edgeID, const double x, const double y, double angle, const int keepRouteFlag) {
    MSPerson* p = getPerson(personID);
    bool keepRoute = (keepRouteFlag == 1);
    bool mayLeaveNetwork = (keepRouteFlag == 2);
    Position pos(x, y);
#ifdef DEBUG_MOVEXY
    const double origAngle = angle;
#endif
    // angle must be in [0,360] because it will be compared against those returned by naviDegree()
    // angle set to INVALID_DOUBLE_VALUE is ignored in the evaluated and later set to the angle of the matched lane
    if (angle != INVALID_DOUBLE_VALUE) {
        while (angle >= 360.) {
            angle -= 360.;
        }
        while (angle < 0.) {
            angle += 360.;
        }
    }
    Position currentPos = p->getPosition();
#ifdef DEBUG_MOVEXY
    std::cout << std::endl << "begin person " << p->getID() << " lanePos:" << p->getEdgePos() << " edge:" << Named::getIDSecure(p->getEdge()) << "\n";
    std::cout << " want pos:" << pos << " edgeID:" << edgeID <<  " origAngle:" << origAngle << " angle:" << angle << " keepRoute:" << keepRoute << std::endl;
#endif

    ConstMSEdgeVector edges;
    MSLane* lane = nullptr;
    double lanePos;
    double lanePosLat = 0;
    double bestDistance = std::numeric_limits<double>::max();
    int routeOffset = 0;
    bool found = false;
    double maxRouteDistance = 100;

    ConstMSEdgeVector ev;
    ev.push_back(p->getEdge());
    int routeIndex = 0;
    MSLane* currentLane = const_cast<MSLane*>(getSidewalk<MSEdge, MSLane>(p->getEdge()));
    switch (p->getStageType(0)) {
        case MSTransportable::MOVING_WITHOUT_VEHICLE: {
            MSPerson::MSPersonStage_Walking* s = dynamic_cast<MSPerson::MSPersonStage_Walking*>(p->getCurrentStage());
            assert(s != 0);
            ev = s->getEdges();
            routeIndex = (int)(s->getRouteStep() - s->getRoute().begin());
        }
        break;
        default:
            break;
    }
    if (keepRoute) {
        // case a): vehicle is on its earlier route
        //  we additionally assume it is moving forward (SUMO-limit);
        //  note that the route ("edges") is not changed in this case
        found = Helper::moveToXYMap_matchingRoutePosition(pos, edgeID,
                ev, routeIndex,
                bestDistance, &lane, lanePos, routeOffset);
    } else {
        double speed = pos.distanceTo2D(p->getPosition()); // !!!veh->getSpeed();
        found = Helper::moveToXYMap(pos, maxRouteDistance, mayLeaveNetwork, edgeID, angle,
                                    speed, ev, routeIndex, currentLane, p->getEdgePos(), true,
                                    bestDistance, &lane, lanePos, routeOffset, edges);
    }
    if ((found && bestDistance <= maxRouteDistance) || mayLeaveNetwork) {
        // compute lateral offset
        if (found) {
            const double perpDist = lane->getShape().distance2D(pos, false);
            if (perpDist != GeomHelper::INVALID_OFFSET) {
                lanePosLat = perpDist;
                if (!mayLeaveNetwork) {
                    lanePosLat = MIN2(lanePosLat, 0.5 * (lane->getWidth() + p->getVehicleType().getWidth()));
                }
                // figure out whether the offset is to the left or to the right
                PositionVector tmp = lane->getShape();
                try {
                    tmp.move2side(-lanePosLat); // moved to left
                } catch (ProcessError&) {
                    WRITE_WARNING("Could not determine position on lane '" + lane->getID() + " at lateral position " + toString(-lanePosLat) + ".");
                }
                //std::cout << " lane=" << lane->getID() << " posLat=" << lanePosLat << " shape=" << lane->getShape() << " tmp=" << tmp << " tmpDist=" << tmp.distance2D(pos) << "\n";
                if (tmp.distance2D(pos) > perpDist) {
                    lanePosLat = -lanePosLat;
                }
            }
        }
        if (found && !mayLeaveNetwork && MSGlobals::gLateralResolution < 0) {
            // mapped position may differ from pos
            pos = lane->geometryPositionAtOffset(lanePos, -lanePosLat);
        }
        assert((found && lane != 0) || (!found && lane == 0));
        if (angle == INVALID_DOUBLE_VALUE) {
            if (lane != nullptr) {
                angle = GeomHelper::naviDegree(lane->getShape().rotationAtOffset(lanePos));
            } else {
                // compute angle outside road network from old and new position
                angle = GeomHelper::naviDegree(p->getPosition().angleTo2D(pos));
            }
        }
        switch (p->getStageType(0)) {
            case MSTransportable::MOVING_WITHOUT_VEHICLE: {
                Helper::setRemoteControlled(p, pos, lane, lanePos, lanePosLat, angle, routeOffset, edges, MSNet::getInstance()->getCurrentTimeStep());
                break;
            }
            default:
                throw TraCIException("Command moveToXY is not supported for person '" + personID + "' while " + p->getCurrentStageDescription() + ".");
        }
    } else {
        if (lane == nullptr) {
            throw TraCIException("Could not map person '" + personID + "' no road found within " + toString(maxRouteDistance) + "m.");
        } else {
            throw TraCIException("Could not map person '" + personID + "' distance to road is " + toString(bestDistance) + ".");
        }
    }
}
예제 #10
0
void
MSQueueExport::writeLane(OutputDevice& of, const MSLane& lane) {

    //Fahrzeug mit der höchsten Wartezeit
    //Fahrzeug am Ende des Rückstaus

    double queueing_time = 0.0;
    double queueing_length = 0.0;
    double queueing_length2 = 0.0;


    if (lane.getVehicleNumber() != 0) {

        for (std::vector<MSVehicle*>::const_iterator veh = lane.myVehBuffer.begin(); veh != lane.myVehBuffer.end(); ++veh) {

            const MSVehicle& veh_tmp = **veh;
            if (veh_tmp.isOnRoad()) {

                if (veh_tmp.getWaitingSeconds() > 0) {

                    if (veh_tmp.getWaitingSeconds() > queueing_time) {
                        queueing_time = veh_tmp.getWaitingSeconds();
                    }

                    double tmp_length = (lane.getLength() -  veh_tmp.getPositionOnLane()) + veh_tmp.getVehicleType().getLengthWithGap();

                    if (tmp_length > queueing_length) {
                        queueing_length = tmp_length;
                    }


                }

            }

        }


        for (MSLane::VehCont::const_iterator veh = lane.myVehicles.begin(); veh != lane.myVehicles.end(); ++veh) {

            const MSVehicle& veh_tmp = **veh;
            if (veh_tmp.isOnRoad()) {

                if (veh_tmp.getWaitingSeconds() > 0) {

                    if (veh_tmp.getWaitingSeconds() > queueing_time) {
                        queueing_time = veh_tmp.getWaitingSeconds();
                    }

                    double tmp_length = (lane.getLength() - veh_tmp.getPositionOnLane()) + veh_tmp.getVehicleType().getLengthWithGap();

                    if (tmp_length > queueing_length) {
                        queueing_length = tmp_length;
                    }


                }

            }
        }


        //Experimental
        double tmp_length2 = 0.0;

        for (MSLane::VehCont::const_iterator veh = lane.myVehicles.begin(); veh != lane.myVehicles.end(); ++veh) {

            //wenn Fahrzeug langsamer als 5 km/h fährt = Rückstau
            double threshold_velocity = 5 / 3.6;
            const MSVehicle& veh_tmp = **veh;
            if (veh_tmp.isOnRoad()) {

                if (veh_tmp.getSpeed() < (threshold_velocity) && (veh_tmp.getPositionOnLane() > (veh_tmp.getLane()->getLength()) * 0.25))

                {
                    tmp_length2 = (lane.getLength() - veh_tmp.getPositionOnLane()) + veh_tmp.getVehicleType().getLengthWithGap();
                }
                if (tmp_length2 > queueing_length2) {
                    queueing_length2 = tmp_length2;
                }

            }
        }

    }

    //Output
    if (queueing_length > 1 || queueing_length2 > 1) {
        of.openTag("lane") << " id=\"" << lane.getID() << "\"";
        of << " queueing_time=\"" << queueing_time << "\" queueing_length=\"" << queueing_length << "\" queueing_length_experimental=\"" << queueing_length2 << "\"";
        of.closeTag(true);
    }

}
예제 #11
0
void
MSRailSignal::collectConflictLinks(MSLane* toLane, double length,
                                   std::vector<MSLane*>& backwardBlock,
                                   std::vector<MSLink*>& conflictLinks,
                                   LaneSet& visited,
                                   bool checkFoes) {
    while (toLane != nullptr) {
        //std::cout << "collectConflictLinks " << getID() << " toLane=" << toLane->getID() << " length=" << length
        //    << " backward=" << toString(backwardBlock)
        //    << " conflictLinks=" << conflictLinks.size()
        //    << " visited=" << visited.size()
        //    << " checkFoes=" << checkFoes
        //    << "\n";
        const auto& incomingLaneInfos = toLane->getIncomingLanes();
        MSLane* orig = toLane;
        toLane = nullptr;
        for (const auto& ili : incomingLaneInfos) {
            if (ili.viaLink->getDirection() == LINKDIR_TURN) {
                continue;
            }
            if (visited.count(ili.lane) != 0) {
                continue;
            }
            if (ili.viaLink->getTLLogic() != nullptr) {
                conflictLinks.push_back(ili.viaLink);
                continue;
            }
            backwardBlock.push_back(ili.lane);
            visited.insert(ili.lane);
            length += orig->getLength();
            if (length > MAX_BLOCK_LENGTH) {
                if (myNumWarnings < MAX_SIGNAL_WARNINGS) {
                    WRITE_WARNING("incoming conflict block after rail signal junction '" + getID() +
                                  "' exceeds maximum length (stopped searching after lane '" + orig->getID() + "' (length=" + toString(length) + "m).");
                }
                myNumWarnings++;
                return;
            }
            if (toLane == nullptr) {
                toLane = ili.lane;
            } else {
                collectConflictLinks(ili.lane, length, backwardBlock, conflictLinks, visited, false);
            }
        }
        if (checkFoes && orig->isInternal()) {
            // check for crossed tracks
            MSLink* link = orig->getIncomingLanes().front().viaLink;
            if (link->getDirection() != LINKDIR_TURN) {
                for (const MSLane* foeConst : link->getFoeLanes()) {
                    MSLane* foe = const_cast<MSLane*>(foeConst);
                    if (visited.count(foe) == 0) {
                        backwardBlock.push_back(foe);
                        visited.insert(foe);
                        collectConflictLinks(foe, length, backwardBlock, conflictLinks, visited, false);
                    }
                }
            }
        }
    }
}
예제 #12
0
bool
MSLaneChanger::changeOpposite(std::pair<MSVehicle*, SUMOReal> leader) {
    if (!myChangeToOpposite) {
        return false;
    }
    myCandi = findCandidate();
    MSVehicle* vehicle = veh(myCandi);
    MSLane* source = vehicle->getLane();
    if (vehicle->isStopped()) {
        // stopped vehicles obviously should not change lanes. Usually this is
        // prevent by appropriate bestLane distances
        return false;
    }
    const bool isOpposite = vehicle->getLaneChangeModel().isOpposite();
    if (!isOpposite && leader.first == 0) {
        // no reason to change unless there is a leader
        // or we are changing back to the propper direction
        // XXX also check whether the leader is so far away as to be irrelevant
        return false;
    }
    MSLane* opposite = source->getOpposite();
    if (opposite == 0) {
        return false;
    }

    // changing into the opposite direction is always to the left (XXX except for left-hand networkds)
    int direction = isOpposite ? -1 : 1;
    std::pair<MSVehicle*, SUMOReal> neighLead((MSVehicle*)0, -1);

    // preliminary sanity checks for overtaking space
    SUMOReal timeToOvertake;
    SUMOReal spaceToOvertake;
    if (!isOpposite) {
        assert(leader.first != 0);
        // find a leader vehicle with sufficient space ahead for merging back
        const SUMOReal overtakingSpeed = source->getVehicleMaxSpeed(vehicle); // just a guess
        const SUMOReal mergeBrakeGap = vehicle->getCarFollowModel().brakeGap(overtakingSpeed);
        std::pair<MSVehicle*, SUMOReal> columnLeader = leader;
        SUMOReal egoGap = leader.second;
        bool foundSpaceAhead = false;
        SUMOReal seen = leader.second + leader.first->getVehicleType().getLengthWithGap();
        std::vector<MSLane*> conts = vehicle->getBestLanesContinuation();
        while (!foundSpaceAhead) {
            const SUMOReal requiredSpaceAfterLeader = (columnLeader.first->getCarFollowModel().getSecureGap(
                        columnLeader.first->getSpeed(), overtakingSpeed, vehicle->getCarFollowModel().getMaxDecel())
                    + vehicle->getVehicleType().getLengthWithGap());


            // all leader vehicles on the current laneChanger edge are already moved into MSLane::myTmpVehicles
            const bool checkTmpVehicles = (&columnLeader.first->getLane()->getEdge() == &source->getEdge());
            std::pair<MSVehicle* const, SUMOReal> leadLead = columnLeader.first->getLane()->getLeader(
                        columnLeader.first, columnLeader.first->getPositionOnLane(), conts, requiredSpaceAfterLeader + mergeBrakeGap, 
                        checkTmpVehicles);

#ifdef DEBUG_CHANGE_OPPOSITE
            if (DEBUG_COND) {
                std::cout << "   leadLead=" << Named::getIDSecure(leadLead.first) << " gap=" << leadLead.second << "\n";
            }
#endif
            if (leadLead.first == 0) {
                foundSpaceAhead = true;
            } else {
                const SUMOReal requiredSpace = (requiredSpaceAfterLeader
                                                + vehicle->getCarFollowModel().getSecureGap(overtakingSpeed, leadLead.first->getSpeed(), leadLead.first->getCarFollowModel().getMaxDecel()));
                if (leadLead.second > requiredSpace) {
                    foundSpaceAhead = true;
                } else {
#ifdef DEBUG_CHANGE_OPPOSITE
                    if (DEBUG_COND) {
                        std::cout << "   not enough space after columnLeader=" << columnLeader.first->getID() << " required=" << requiredSpace << "\n";
                    }
#endif
                    seen += MAX2((SUMOReal)0, leadLead.second) + leadLead.first->getVehicleType().getLengthWithGap();
                    if (seen > OPPOSITE_OVERTAKING_MAX_LOOKAHEAD) {
#ifdef DEBUG_CHANGE_OPPOSITE
                        if (DEBUG_COND) {
                            std::cout << "   cannot changeOpposite due to insufficient free space after columnLeader (seen=" << seen << " columnLeader=" << columnLeader.first->getID() << ")\n";
                        }
#endif
                        return false;
                    }
                    // see if merging after leadLead is possible
                    egoGap += columnLeader.first->getVehicleType().getLengthWithGap() + leadLead.second;
                    columnLeader = leadLead;
#ifdef DEBUG_CHANGE_OPPOSITE
                    if (DEBUG_COND) {
                        std::cout << "   new columnLeader=" << columnLeader.first->getID() << "\n";
                    }
#endif
                }
            }
        }
#ifdef DEBUG_CHANGE_OPPOSITE
        if (DEBUG_COND) {
            std::cout << "   compute time/space to overtake for columnLeader=" << columnLeader.first->getID() << " gap=" << columnLeader.second << "\n";
        }
#endif
        computeOvertakingTime(vehicle, columnLeader.first, egoGap, timeToOvertake, spaceToOvertake);
        // check for upcoming stops
        if (vehicle->nextStopDist() < spaceToOvertake) {
#ifdef DEBUG_CHANGE_OPPOSITE
            if (DEBUG_COND) {
                std::cout << "   cannot changeOpposite due to upcoming stop (dist=" << vehicle->nextStopDist() << " spaceToOvertake=" << spaceToOvertake << ")\n";
            }
#endif
            return false;
        }
        neighLead = opposite->getOppositeLeader(vehicle, timeToOvertake * opposite->getSpeedLimit() * 2 + spaceToOvertake, true);

#ifdef DEBUG_CHANGE_OPPOSITE
        if (DEBUG_COND) {
            std::cout << SIMTIME
                      << " veh=" << vehicle->getID()
                      << " changeOpposite opposite=" << opposite->getID()
                      << " lead=" << Named::getIDSecure(leader.first)
                      << " timeToOvertake=" << timeToOvertake
                      << " spaceToOvertake=" << spaceToOvertake
                      << "\n";
        }
#endif

        // check for dangerous oncoming leader
        if (neighLead.first != 0) {
            const MSVehicle* oncoming = neighLead.first;

#ifdef DEBUG_CHANGE_OPPOSITE
            if (DEBUG_COND) {
                std::cout << SIMTIME
                          << " oncoming=" << oncoming->getID()
                          << " oncomingGap=" << neighLead.second
                          << " leaderGap=" << leader.second
                          << "\n";
            }
#endif
            if (neighLead.second - spaceToOvertake - timeToOvertake * oncoming->getSpeed() < 0) {

#ifdef DEBUG_CHANGE_OPPOSITE
                if (DEBUG_COND) {
                    std::cout << "   cannot changeOpposite due to dangerous oncoming\n";
                }
#endif
                return false;
            }
        }
    } else {
        timeToOvertake = -1;
        // look forward as far as possible
        spaceToOvertake = std::numeric_limits<SUMOReal>::max();
        leader = source->getOppositeLeader(vehicle, OPPOSITE_OVERTAKING_ONCOMING_LOOKAHEAD, true);
        // -1 will use getMaximumBrakeDist() as look-ahead distance
        neighLead = opposite->getOppositeLeader(vehicle, -1, false); 
    }

    // compute remaining space on the opposite side
    // 1. the part that remains on the current lane
    SUMOReal usableDist = isOpposite ? vehicle->getPositionOnLane() : source->getLength() - vehicle->getPositionOnLane();
    if (usableDist < spaceToOvertake) {
        // look forward along the next lanes
        const std::vector<MSLane*>& bestLaneConts = vehicle->getBestLanesContinuation();
        assert(bestLaneConts.size() >= 1);
        std::vector<MSLane*>::const_iterator it = bestLaneConts.begin() + 1;
        while (usableDist < spaceToOvertake && it != bestLaneConts.end()) {
#ifdef DEBUG_CHANGE_OPPOSITE
            if (DEBUG_COND) {
                std::cout << "      usableDist=" << usableDist << " opposite=" << Named::getIDSecure((*it)->getOpposite()) << "\n";
            }
#endif
            if ((*it)->getOpposite() == 0) {
                // opposite lane ends
                break;
            }
            // do not overtake past a minor link or turn
            if (*(it - 1) != 0) {
                MSLink* link = MSLinkContHelper::getConnectingLink(**(it - 1), **it);
                if (link == 0 || !link->havePriority() || link->getState() == LINKSTATE_ZIPPER || link->getDirection() != LINKDIR_STRAIGHT) {
                    break;
                }
            }
            usableDist += (*it)->getLength();
            ++it;
        }
    }
    if (!isOpposite && usableDist < spaceToOvertake) {
#ifdef DEBUG_CHANGE_OPPOSITE
        if (DEBUG_COND) {
            std::cout << "   cannot changeOpposite due to insufficient space (seen=" << usableDist << " spaceToOvertake=" << spaceToOvertake << ")\n";
        }
#endif
        return false;
    }
#ifdef DEBUG_CHANGE_OPPOSITE
    if (DEBUG_COND) {
        std::cout << "   usableDist=" << usableDist << " spaceToOvertake=" << spaceToOvertake << " timeToOvertake=" << timeToOvertake << "\n";
    }
#endif

    // compute wish to change
    std::vector<MSVehicle::LaneQ> preb = vehicle->getBestLanes();
    if (isOpposite) {
        // compute the remaining distance that can be drive on the opposite side
        // this value will put into LaneQ.length of the leftmost lane
        // @note: length counts from the start of the current lane
        // @note: see MSLCM_LC2013::_wantsChange @1092 (isOpposite()
        MSVehicle::LaneQ& laneQ = preb[preb.size() - 1];
        // position on the target lane 
        const SUMOReal forwardPos = source->getOppositePos(vehicle->getPositionOnLane());

        // consider usableDist (due to minor links or end of opposite lanes)
        laneQ.length = MIN2(laneQ.length, usableDist + forwardPos);
        // consider upcoming stops
        laneQ.length = MIN2(laneQ.length, vehicle->nextStopDist() + forwardPos);
        // consider oncoming leaders
        if (leader.first != 0) {
            laneQ.length = MIN2(laneQ.length, leader.second / 2 + forwardPos);
#ifdef DEBUG_CHANGE_OPPOSITE
        if (DEBUG_COND) {
            std::cout << SIMTIME << " found oncoming leader=" << leader.first->getID() << " gap=" << leader.second << "\n";
        }
#endif
            leader.first = 0; // ignore leader after this
        } 
#ifdef DEBUG_CHANGE_OPPOSITE
        if (DEBUG_COND) {
            std::cout << SIMTIME << " veh=" << vehicle->getID() << " remaining dist=" << laneQ.length - forwardPos << " forwardPos=" << forwardPos << " laneQ.length=" << laneQ.length << "\n";
        }
#endif
    }
    std::pair<MSVehicle* const, SUMOReal> neighFollow = opposite->getOppositeFollower(vehicle);
    int state = checkChange(direction, opposite, leader, neighLead, neighFollow, preb);

    bool changingAllowed = (state & LCA_BLOCKED) == 0;
    // change if the vehicle wants to and is allowed to change
    if ((state & LCA_WANTS_LANECHANGE) != 0 && changingAllowed
            // do not change to the opposite direction for cooperative reasons
            && (isOpposite || (state & LCA_COOPERATIVE) == 0)) {
        vehicle->getLaneChangeModel().startLaneChangeManeuver(source, opposite, direction);
        /// XXX use a dedicated transformation function
        vehicle->myState.myPos = source->getOppositePos(vehicle->myState.myPos);
        /// XXX compute a better lateral position
        opposite->forceVehicleInsertion(vehicle, vehicle->getPositionOnLane(), MSMoveReminder::NOTIFICATION_LANE_CHANGE, 0);
        if (!isOpposite) {
            vehicle->myState.myBackPos = source->getOppositePos(vehicle->myState.myBackPos);
        }
#ifdef DEBUG_CHANGE_OPPOSITE
        if (DEBUG_COND) {
            std::cout << SIMTIME << " changing to opposite veh=" << vehicle->getID() << " dir=" << direction << " opposite=" << Named::getIDSecure(opposite) << " state=" << state << "\n";
        }
#endif
        return true;
    }
#ifdef DEBUG_CHANGE_OPPOSITE
    if (DEBUG_COND) {
        std::cout << SIMTIME << " not changing to opposite veh=" << vehicle->getID() << " dir=" << direction 
            << " opposite=" << Named::getIDSecure(opposite) << " state=" << toString((LaneChangeAction)state) << "\n";
    }
#endif
    return false;
}
예제 #13
0
void
NLDetectorBuilder::buildE2Detector(const std::string& id, std::vector<MSLane*> lanes, double pos, double endPos,
                                   const std::string& device, SUMOTime frequency,
                                   SUMOTime haltingTimeThreshold, double haltingSpeedThreshold, double jamDistThreshold,
                                   const std::string& vTypes, bool friendlyPos, bool showDetector,
                                   MSTLLogicControl::TLSLogicVariants* tlls, MSLane* toLane) {

    bool tlsGiven = tlls != 0;
    bool toLaneGiven = toLane != 0;
    assert(pos != std::numeric_limits<double>::max());
    assert(endPos != std::numeric_limits<double>::max());
    assert(lanes.size() != 0);

    MSLane* firstLane = lanes[0];
    MSLane* lastLane = lanes[lanes.size() - 1];

    // Check positioning
    if (pos >= firstLane->getLength() || (pos < 0 && -pos > firstLane->getLength())) {
        std::stringstream ss;
        ss << "The given position (=" << pos << ") for detector '" << id
           << "' does not lie on the given lane '" << firstLane->getID()
           << "' with length " << firstLane->getLength();
        if (friendlyPos) {
            double newPos = pos > 0 ? firstLane->getLength() - POSITION_EPS : 0.;
            ss << " (adjusting to new position " << newPos;
            WRITE_WARNING(ss.str());
            pos = newPos;
        } else {
            ss << " (0 <= pos < lane->getLength() is required)";
            throw InvalidArgument(ss.str());
        }
    }
    if (endPos > lastLane->getLength() || (endPos <= 0 && -endPos >= lastLane->getLength())) {
        std::stringstream ss;
        ss << "The given end position (=" << endPos << ") for detector '" << id
           << "' does not lie on the given lane '" << lastLane->getID()
           << "' with length " << lastLane->getLength();
        if (friendlyPos) {
            double newEndPos = endPos > 0 ? lastLane->getLength() : POSITION_EPS;
            ss << " (adjusting to new position " << newEndPos;
            WRITE_WARNING(ss.str());
            pos = newEndPos;
        } else {
            ss << " (0 <= pos < lane->getLength() is required)";
            throw InvalidArgument(ss.str());
        }
    }

    MSE2Collector* det = 0;
    if (tlsGiven) {
        // Detector connected to TLS
        det = createE2Detector(id, DU_USER_DEFINED, lanes, pos, endPos, haltingTimeThreshold, haltingSpeedThreshold, jamDistThreshold, vTypes, showDetector);
        myNet.getDetectorControl().add(SUMO_TAG_LANE_AREA_DETECTOR, det);
        // add the file output (XXX: Where's the corresponding delete?)
        if (toLaneGiven) {
            // Detector also associated to specific link
            MSLane* lastLane = det->getLastLane();
            MSLink* link = MSLinkContHelper::getConnectingLink(*lastLane, *toLane);
            if (link == 0) {
                throw InvalidArgument(
                    "The detector '" + id + "' cannot be build as no connection between lanes '"
                    + lastLane->getID() + "' and '" + toLane->getID() + "' exists.");
            }
            new Command_SaveTLCoupledLaneDet(*tlls, det, myNet.getCurrentTimeStep(), OutputDevice::getDevice(device), link);
        } else {
            // detector for tls but without specific link
            new Command_SaveTLCoupledDet(*tlls, det, myNet.getCurrentTimeStep(), OutputDevice::getDevice(device));
        }
    } else {
        // User specified detector for xml-output
        checkSampleInterval(frequency, SUMO_TAG_E2DETECTOR, id);

        det = createE2Detector(id, DU_USER_DEFINED, lanes, pos, endPos, haltingTimeThreshold, haltingSpeedThreshold, jamDistThreshold, vTypes, showDetector);
        myNet.getDetectorControl().add(SUMO_TAG_LANE_AREA_DETECTOR, det, device, frequency);
    }

}
void
MSAgentbasedTrafficLightLogic::init(NLDetectorBuilder &nb) throw(ProcessError) {
    SUMOReal det_offset = TplConvert<char>::_2SUMOReal(myParameter.find("detector_offset")->second.c_str());
    LaneVectorVector::const_iterator i2;
    LaneVector::const_iterator i;
    // build the detectors
    for (i2=myLanes.begin(); i2!=myLanes.end(); ++i2) {
        const LaneVector &lanes = *i2;
        for (i=lanes.begin(); i!=lanes.end(); i++) {
            MSLane *lane = (*i);
            // Build the lane state detetcor and set it into the container
            std::string id = "TL_" + myID + "_" + myProgramID + "_E2OverLanesDetectorStartingAt_" + lane->getID();

            if (myE2Detectors.find(lane)==myE2Detectors.end()) {
                MS_E2_ZS_CollectorOverLanes* det =
                    nb.buildMultiLaneE2Det(id,
                                           DU_TL_CONTROL, lane, 0, det_offset,
                                           /*haltingTimeThreshold!!!*/ 1,
                                           /*haltingSpeedThreshold!!!*/(SUMOReal)(5.0/3.6),
                                           /*jamDistThreshold!!!*/ 10);
                myE2Detectors[lane] = det;
            }
        }
    }


    // initialise the duration
    unsigned int tCycleIst = 0;          // the actual cycletime
    unsigned int tCycleMin = 0;          // the minimum cycle time
    unsigned int tDeltaGreen = 0;         // the difference between the actual cycle time and the required cycle time

    /// Calculation of starting values
    for (unsigned int actStep = 0; actStep!=myPhases.size(); actStep++) {
        unsigned int dur = (unsigned int) myPhases[actStep]->duration;
        tCycleIst = tCycleIst + dur;
        if (myPhases[actStep]->isGreenPhase()) {
            unsigned int mindur = (unsigned int) myPhases[actStep]->minDuration;
            tCycleMin = tCycleMin + mindur;
        } else {
            tCycleMin = tCycleMin + dur;
        }
    }
    if (tCycle < tCycleMin) {
        tCycle = tCycleMin;
    }
    if (tCycleIst < tCycle) {
        tDeltaGreen = tCycle - tCycleIst;
        lengthenCycleTime(tDeltaGreen);
    }
    if (tCycleIst > tCycle) {
        tDeltaGreen = tCycleIst - tCycle;
        cutCycleTime(tDeltaGreen);
    }
}
예제 #15
0
bool
MSLaneChanger::changeOpposite(std::pair<MSVehicle*, SUMOReal> leader) {
    if (!myChangeToOpposite) {
        return false;
    }
    myCandi = findCandidate();
    MSVehicle* vehicle = veh(myCandi);
    MSLane* source = vehicle->getLane();
    if (vehicle->isStopped()) {
        // stopped vehicles obviously should not change lanes. Usually this is
        // prevent by appropriate bestLane distances
        return false;
    }
    const bool isOpposite = vehicle->getLaneChangeModel().isOpposite();
    if (!isOpposite && leader.first == 0) {
        // no reason to change unless there is a leader
        // or we are changing back to the propper direction
        // XXX also check whether the leader is so far away as to be irrelevant
        return false;
    }
    if (!source->getEdge().canChangeToOpposite()) {
        return false;
    }
    MSLane* opposite = source->getOpposite();
    if (opposite == 0) {
        return false;
    }

    // changing into the opposite direction is always to the left (XXX except for left-hand networkds)
    int direction = vehicle->getLaneChangeModel().isOpposite() ? -1 : 1;
    std::pair<MSVehicle*, SUMOReal> neighLead((MSVehicle*)0, -1);

    // preliminary sanity checks for overtaking space
    if (!isOpposite) {
        assert(leader.first != 0);
        // find a leader vehicle with sufficient space ahead for merging back
        const SUMOReal overtakingSpeed = source->getVehicleMaxSpeed(vehicle); // just a guess
        const SUMOReal mergeBrakeGap = vehicle->getCarFollowModel().brakeGap(overtakingSpeed);
        const SUMOReal maxLookAhead = 150; // just a guess
        std::pair<MSVehicle*, SUMOReal> columnLeader = leader;
        SUMOReal egoGap = leader.second;
        bool foundSpaceAhead = false;
        SUMOReal seen = leader.second + leader.first->getVehicleType().getLengthWithGap();
        std::vector<MSLane*> conts = vehicle->getBestLanesContinuation();
        while (!foundSpaceAhead) {
            const SUMOReal requiredSpaceAfterLeader = (columnLeader.first->getCarFollowModel().getSecureGap(
                        columnLeader.first->getSpeed(), overtakingSpeed, vehicle->getCarFollowModel().getMaxDecel())
                    + vehicle->getVehicleType().getLengthWithGap());


            std::pair<MSVehicle* const, SUMOReal> leadLead = columnLeader.first->getLane()->getLeader(
                        columnLeader.first, columnLeader.first->getPositionOnLane(), conts, requiredSpaceAfterLeader + mergeBrakeGap, true);

#ifdef DEBUG_CHANGE_OPPOSITE
            if (DEBUG_COND) {
            	std::cout << "   leadLead=" << Named::getIDSecure(leadLead.first) << " gap=" << leadLead.second << "\n";
            }
#endif
            if (leadLead.first == 0) {
                foundSpaceAhead = true;
            } else {
                const SUMOReal requiredSpace = (requiredSpaceAfterLeader
                                                + vehicle->getCarFollowModel().getSecureGap(overtakingSpeed, leadLead.first->getSpeed(), leadLead.first->getCarFollowModel().getMaxDecel()));
                if (leadLead.second > requiredSpace) {
                    foundSpaceAhead = true;
                } else {
#ifdef DEBUG_CHANGE_OPPOSITE
                	if (DEBUG_COND) {
                		std::cout << "   not enough space after columnLeader=" << leadLead.first->getID() << " gap=" << leadLead.second << " required=" << requiredSpace << "\n";
                	}
#endif
                    seen += leadLead.second + leadLead.first->getVehicleType().getLengthWithGap();
                    if (seen > maxLookAhead) {
#ifdef DEBUG_CHANGE_OPPOSITE
                    	if (DEBUG_COND) {
                    		std::cout << "   cannot changeOpposite due to insufficient free space after columnLeader (seen=" << seen << " columnLeader=" << leadLead.first->getID() << ")\n";
                    	}
#endif
                        return false;
                    }
                    // see if merging after leadLead is possible
                    egoGap += columnLeader.first->getVehicleType().getLengthWithGap() + leadLead.second;
                    columnLeader = leadLead;
#ifdef DEBUG_CHANGE_OPPOSITE
    if (DEBUG_COND) {
                        std::cout << "   new columnLeader=" << columnLeader.first->getID() << "\n";
                    }
#endif
                }
            }
        }
#ifdef DEBUG_CHANGE_OPPOSITE
    if (DEBUG_COND) {
            std::cout << "   compute time/space to overtake for columnLeader=" << columnLeader.first->getID() << " gap=" << columnLeader.second << "\n";
        }
#endif
        SUMOReal timeToOvertake;
        SUMOReal spaceToOvertake;
        computeOvertakingTime(vehicle, columnLeader.first, egoGap, timeToOvertake, spaceToOvertake);
        // check for upcoming stops
        if (vehicle->nextStopDist() < spaceToOvertake) {
#ifdef DEBUG_CHANGE_OPPOSITE
    if (DEBUG_COND) {
                std::cout << "   cannot changeOpposite due to upcoming stop (dist=" << vehicle->nextStopDist() << " spaceToOvertake=" << spaceToOvertake << ")\n";
            }
#endif
            return false;
        }
        neighLead = opposite->getOppositeLeader(vehicle, timeToOvertake * opposite->getSpeedLimit() * 2 + spaceToOvertake);

#ifdef DEBUG_CHANGE_OPPOSITE
    if (DEBUG_COND) {
            std::cout << SIMTIME
                      << " veh=" << vehicle->getID()
                      << " changeOpposite opposite=" << opposite->getID()
                      << " lead=" << Named::getIDSecure(leader.first)
                      << " oncoming=" << Named::getIDSecure(neighLead.first)
                      << " timeToOvertake=" << timeToOvertake
                      << " spaceToOvertake=" << spaceToOvertake
                      << "\n";
        }
#endif

        // check for dangerous oncoming leader
        if (!vehicle->getLaneChangeModel().isOpposite() && neighLead.first != 0) {
            const MSVehicle* oncoming = neighLead.first;
            /// XXX what about overtaking multiple vehicles?

#ifdef DEBUG_CHANGE_OPPOSITE
            if (DEBUG_COND) {
            	std::cout << SIMTIME
            			<< " timeToOvertake=" << timeToOvertake
            			<< " spaceToOvertake=" << spaceToOvertake
            			<< " oncomingGap=" << neighLead.second
            			<< " leaderGap=" << leader.second
            			<< "\n";
            }
#endif
            if (neighLead.second - spaceToOvertake - timeToOvertake * oncoming->getSpeed() < 0) {

#ifdef DEBUG_CHANGE_OPPOSITE
            	if (DEBUG_COND) {
            		std::cout << "   cannot changeOpposite due to dangerous oncoming\n";
            	}
#endif
                return false;
            }
        }
        // check for sufficient space on the opposite side
        seen = source->getLength() - vehicle->getPositionOnLane();
        if (!vehicle->getLaneChangeModel().isOpposite() && seen < spaceToOvertake) {
            const std::vector<MSLane*>& bestLaneConts = vehicle->getBestLanesContinuation();
            assert(bestLaneConts.size() >= 1);
            std::vector<MSLane*>::const_iterator it = bestLaneConts.begin() + 1;
            while (seen < spaceToOvertake && it != bestLaneConts.end()) {
                if ((*it)->getOpposite() == 0) {
                    break;
                }
                // do not overtake past a minor link
                if (*(it - 1) != 0) {
                    MSLink* link = MSLinkContHelper::getConnectingLink(**(it - 1), **it);
                    if (link == 0 || !link->havePriority() || link->getState() == LINKSTATE_ZIPPER) {
                        break;
                    }
                }
                seen += (*it)->getLength();
            }
            if (seen < spaceToOvertake) {
#ifdef DEBUG_CHANGE_OPPOSITE
            	if (DEBUG_COND) {
            		std::cout << "   cannot changeOpposite due to insufficient space (seen=" << seen << " spaceToOvertake=" << spaceToOvertake << ")\n";
            	}
#endif
                return false;
            }
#ifdef DEBUG_CHANGE_OPPOSITE
            if (DEBUG_COND) {
            	std::cout << "   seen=" << seen << " spaceToOvertake=" << spaceToOvertake << " timeToOvertake=" << timeToOvertake << "\n";
            }
#endif
        }
    } else {
        /// XXX compute sensible distance
        leader = source->getOppositeLeader(vehicle, 200);
        neighLead = opposite->getOppositeLeader(vehicle, -1);
    }

    // compute wish to change
    std::vector<MSVehicle::LaneQ> preb = vehicle->getBestLanes();
    if (isOpposite && leader.first != 0) {
        MSVehicle::LaneQ& laneQ = preb[preb.size() - 1];
        /// XXX compute sensible usable dist
        laneQ.length -= MIN2(laneQ.length, opposite->getOppositePos(vehicle->getPositionOnLane()) + leader.second / 2);
        leader.first = 0; // ignore leader
    }
    std::pair<MSVehicle* const, SUMOReal> neighFollow = opposite->getOppositeFollower(vehicle);
    int state = checkChange(direction, opposite, leader, neighLead, neighFollow, preb);

    bool changingAllowed = (state & LCA_BLOCKED) == 0;
    // change if the vehicle wants to and is allowed to change
    if ((state & LCA_WANTS_LANECHANGE) != 0 && changingAllowed) {
        vehicle->getLaneChangeModel().startLaneChangeManeuver(source, opposite, direction);
        /// XXX use a dedicated transformation function
        vehicle->myState.myPos = source->getOppositePos(vehicle->myState.myPos);
        vehicle->myState.myBackPos = source->getOppositePos(vehicle->myState.myBackPos);
        /// XXX compute a bette lateral position
        opposite->forceVehicleInsertion(vehicle, vehicle->getPositionOnLane(), MSMoveReminder::NOTIFICATION_LANE_CHANGE, 0);
#ifdef DEBUG_CHANGE_OPPOSITE
        if (DEBUG_COND) {
        	std::cout << SIMTIME << " changing to opposite veh=" << vehicle->getID() << " dir=" << direction << " opposite=" << Named::getIDSecure(opposite) << " state=" << state << "\n";
        }
#endif
        return true;
    }
#ifdef DEBUG_CHANGE_OPPOSITE
    if (DEBUG_COND) {
    	std::cout << SIMTIME << " not changing to opposite veh=" << vehicle->getID() << " dir=" << direction << " opposite=" << Named::getIDSecure(opposite) << " state=" << state << "\n";
    }
#endif
    return false;
}