SUMO - Simulation of Urban MObility

MSRouteHandler.cpp

Go to the documentation of this file.
00001 /****************************************************************************/
00007 // Parser and container for routes during their loading
00008 /****************************************************************************/
00009 // SUMO, Simulation of Urban MObility; see http://sumo.sourceforge.net/
00010 // Copyright (C) 2001-2011 DLR (http://www.dlr.de/) and contributors
00011 /****************************************************************************/
00012 //
00013 //   This program is free software; you can redistribute it and/or modify
00014 //   it under the terms of the GNU General Public License as published by
00015 //   the Free Software Foundation; either version 2 of the License, or
00016 //   (at your option) any later version.
00017 //
00018 /****************************************************************************/
00019 
00020 
00021 // ===========================================================================
00022 // included modules
00023 // ===========================================================================
00024 #ifdef _MSC_VER
00025 #include <windows_config.h>
00026 #else
00027 #include <config.h>
00028 #endif
00029 
00030 #include <string>
00031 #include <map>
00032 #include <vector>
00033 #include <microsim/MSRoute.h>
00034 #include <microsim/MSEdge.h>
00035 #include <microsim/MSVehicleType.h>
00036 #include <microsim/MSVehicle.h>
00037 #include <microsim/MSEdge.h>
00038 #include <microsim/MSInsertionControl.h>
00039 #include <microsim/MSVehicleControl.h>
00040 #include <microsim/MSLane.h>
00041 #include "MSRouteHandler.h"
00042 #include "MSPersonControl.h"
00043 #include <utils/xml/SUMOSAXHandler.h>
00044 #include <utils/xml/SUMOXMLDefinitions.h>
00045 #include <utils/common/MsgHandler.h>
00046 #include <utils/common/StringTokenizer.h>
00047 #include <utils/common/UtilExceptions.h>
00048 #include <utils/options/OptionsCont.h>
00049 #include "MSNet.h"
00050 
00051 #include <microsim/trigger/MSBusStop.h>
00052 #include <microsim/MSGlobals.h>
00053 #include <utils/xml/SUMOVehicleParserHelper.h>
00054 
00055 #ifdef CHECK_MEMORY_LEAKS
00056 #include <foreign/nvwa/debug_new.h>
00057 #endif // CHECK_MEMORY_LEAKS
00058 
00059 
00060 // ===========================================================================
00061 // method definitions
00062 // ===========================================================================
00063 MSRouteHandler::MSRouteHandler(const std::string& file,
00064                                bool addVehiclesDirectly) :
00065     SUMOSAXHandler(file),
00066     myVehicleParameter(0),
00067     myLastDepart(0),
00068     myActivePlan(0),
00069     myAddVehiclesDirectly(addVehiclesDirectly),
00070     myCurrentVTypeDistribution(0),
00071     myCurrentRouteDistribution(0),
00072     myCurrentVType(0),
00073     myScale(-1.),
00074     myHaveWarnedAboutDeprecatedFriendlyPos(false),
00075     myHaveWarnedAboutDeprecatedBusStop(false),
00076     myHaveWarnedAboutDeprecatedVType(false),
00077     myHaveWarnedAboutDeprecatedVTypeDistribution(false),
00078     myHaveWarnedAboutDeprecatedVTypes(false),
00079     myHaveWarnedAboutDeprecatedRefID(false) {
00080     OptionsCont& oc = OptionsCont::getOptions();
00081     if (oc.isSet("incremental-dua-step")) {
00082         myScale = oc.getInt("incremental-dua-step") / static_cast<SUMOReal>(oc.getInt("incremental-dua-base"));
00083     }
00084     if (oc.isSet("scale")) {
00085         myScale = oc.getFloat("scale");
00086     }
00087     myActiveRoute.reserve(100);
00088 }
00089 
00090 
00091 MSRouteHandler::~MSRouteHandler() throw() {
00092 }
00093 
00094 
00095 SUMOTime
00096 MSRouteHandler::getLastDepart() const {
00097     return myLastDepart;
00098 }
00099 
00100 
00101 bool
00102 MSRouteHandler::checkLastDepart() {
00103     if (myVehicleParameter->departProcedure == DEPART_GIVEN) {
00104         if (!myAddVehiclesDirectly && myVehicleParameter->depart < myLastDepart) {
00105             WRITE_WARNING("Route file should be sorted by departure time, ignoring '" + myVehicleParameter->id + "'!");
00106             return false;
00107         }
00108         myLastDepart = myVehicleParameter->depart;
00109     }
00110     return true;
00111 }
00112 
00113 
00114 void
00115 MSRouteHandler::myStartElement(int element,
00116                                const SUMOSAXAttributes& attrs) throw(ProcessError) {
00117     switch (element) {
00118     case SUMO_TAG_VEHICLE:
00119         delete myVehicleParameter;
00120         myVehicleParameter = SUMOVehicleParserHelper::parseVehicleAttributes(attrs);
00121         break;
00122     case SUMO_TAG_PERSON:
00123         delete myVehicleParameter;
00124         myVehicleParameter = SUMOVehicleParserHelper::parseVehicleAttributes(attrs);
00125         myActivePlan = new MSPerson::MSPersonPlan();
00126         break;
00127     case SUMO_TAG_RIDE: {
00128         const std::string pid = myVehicleParameter->id;
00129         bool ok = true;
00130         MSEdge* from = 0;
00131         if (attrs.hasAttribute(SUMO_ATTR_FROM)) {
00132             const std::string fromID = attrs.getStringReporting(SUMO_ATTR_FROM, pid.c_str(), ok);
00133             from = MSEdge::dictionary(fromID);
00134             if (from==0) {
00135                 throw ProcessError("The from edge '" + fromID + "' within a ride of person '" + pid + "' is not known.");
00136             }
00137             if (!myActivePlan->empty() && &myActivePlan->back()->getDestination() != from) {
00138                 throw ProcessError("Disconnected plan for person '" + myVehicleParameter->id + "' (" + fromID + "!=" + myActivePlan->back()->getDestination().getID() + ").");
00139             }
00140             if (myActivePlan->empty()) {
00141                 myActivePlan->push_back(new MSPerson::MSPersonStage_Waiting(*from, -1, myVehicleParameter->depart));
00142             }
00143         }
00144         const std::string toID = attrs.getStringReporting(SUMO_ATTR_TO, pid.c_str(), ok);
00145         MSEdge* to = MSEdge::dictionary(toID);
00146         if (to==0) {
00147             throw ProcessError("The to edge '" + toID + "' within a ride of person '" + pid + "' is not known.");
00148         }
00149         const std::string desc = attrs.getStringReporting(SUMO_ATTR_LINES, pid.c_str(), ok);
00150         StringTokenizer st(desc);
00151         myActivePlan->push_back(new MSPerson::MSPersonStage_Driving(*to, st.getVector()));
00152         break;
00153     }
00154     case SUMO_TAG_WALK: {
00155         myActiveRoute.clear();
00156         bool ok = true;
00157         MSEdge::parseEdgesList(attrs.getStringReporting(SUMO_ATTR_EDGES, myVehicleParameter->id.c_str(), ok), myActiveRoute, myActiveRouteID);
00158         if (myActiveRoute.empty()) {
00159             throw ProcessError("No edges to walk for person '" + myVehicleParameter->id + "'.");
00160         }
00161         if (!myActivePlan->empty() && &myActivePlan->back()->getDestination() != myActiveRoute.front()) {
00162             throw ProcessError("Disconnected plan for person '" + myVehicleParameter->id + "' (" + myActiveRoute.front()->getID() + "!=" + myActivePlan->back()->getDestination().getID() + ").");
00163         }
00164         if (myActivePlan->empty()) {
00165             myActivePlan->push_back(new MSPerson::MSPersonStage_Waiting(*myActiveRoute.front(), -1, myVehicleParameter->depart));
00166         }
00167         const SUMOTime duration = attrs.getOptSUMOTimeReporting(SUMO_ATTR_DURATION, 0, ok, -1);
00168         const SUMOReal speed = attrs.getOptSUMORealReporting(SUMO_ATTR_SPEED, 0, ok, -1);
00169         myActivePlan->push_back(new MSPerson::MSPersonStage_Walking(myActiveRoute, duration, speed));
00170         myActiveRoute.clear();
00171         break;
00172     }
00173     case SUMO_TAG_FLOW:
00174         delete myVehicleParameter;
00175         myVehicleParameter = SUMOVehicleParserHelper::parseFlowAttributes(attrs);
00176         if (attrs.hasAttribute(SUMO_ATTR_FROM) && attrs.hasAttribute(SUMO_ATTR_TO)) {
00177             myActiveRouteID = "!" + myVehicleParameter->id;
00178             bool ok = true;
00179             MSEdge::parseEdgesList(attrs.getStringReporting(SUMO_ATTR_FROM, myVehicleParameter->id.c_str(), ok),
00180                                    myActiveRoute, "for vehicle '" + myVehicleParameter->id + "'");
00181             MSEdge::parseEdgesList(attrs.getStringReporting(SUMO_ATTR_TO, myVehicleParameter->id.c_str(), ok),
00182                                    myActiveRoute, "for vehicle '" + myVehicleParameter->id + "'");
00183             closeRoute();
00184         }
00185         break;
00186     case SUMO_TAG_VTYPE__DEPRECATED:
00187         if (!myHaveWarnedAboutDeprecatedVType) {
00188             myHaveWarnedAboutDeprecatedVType = true;
00189             WRITE_WARNING("'" + toString(SUMO_TAG_VTYPE__DEPRECATED) + "' is deprecated; please use '" + toString(SUMO_TAG_VTYPE) + "'.");
00190         }
00191     case SUMO_TAG_VTYPE:
00192         myCurrentVType = SUMOVehicleParserHelper::beginVTypeParsing(attrs);
00193         break;
00194     case SUMO_TAG_VTYPE_DISTRIBUTION__DEPRECATED:
00195         if (!myHaveWarnedAboutDeprecatedVTypeDistribution) {
00196             myHaveWarnedAboutDeprecatedVTypeDistribution = true;
00197             WRITE_WARNING("'" + toString(SUMO_TAG_VTYPE_DISTRIBUTION__DEPRECATED) + "' is deprecated; please use '" + toString(SUMO_TAG_VTYPE_DISTRIBUTION) + "'.");
00198         }
00199     case SUMO_TAG_VTYPE_DISTRIBUTION:
00200         openVehicleTypeDistribution(attrs);
00201         break;
00202     case SUMO_TAG_ROUTE:
00203         openRoute(attrs);
00204         break;
00205     case SUMO_TAG_ROUTE_DISTRIBUTION:
00206         openRouteDistribution(attrs);
00207         break;
00208     case SUMO_TAG_STOP:
00209         addStop(attrs);
00210         break;
00211     case SUMO_TAG_TRIP__DEPRECATED:
00212     case SUMO_TAG_TRIP: {
00213         bool ok = true;
00214         myVehicleParameter = SUMOVehicleParserHelper::parseVehicleAttributes(attrs);
00215         myVehicleParameter->setParameter |= VEHPARS_FORCE_REROUTE;
00216         myActiveRouteID = "!" + myVehicleParameter->id;
00217         if (attrs.hasAttribute(SUMO_ATTR_FROM) || !myVehicleParameter->wasSet(VEHPARS_TAZ_SET)) {
00218             MSEdge::parseEdgesList(attrs.getStringReporting(SUMO_ATTR_FROM, myVehicleParameter->id.c_str(), ok),
00219                                    myActiveRoute, "for vehicle '" + myVehicleParameter->id + "'");
00220             MSEdge::parseEdgesList(attrs.getStringReporting(SUMO_ATTR_TO, myVehicleParameter->id.c_str(), ok),
00221                                    myActiveRoute, "for vehicle '" + myVehicleParameter->id + "'");
00222         } else {
00223             const MSEdge* fromTaz = MSEdge::dictionary(myVehicleParameter->fromTaz+"-source");
00224             if (fromTaz == 0) {
00225                 WRITE_ERROR("Source district '" + myVehicleParameter->fromTaz + "' not known for '" + myVehicleParameter->id + "'!");
00226             } else if (fromTaz->getNoFollowing() == 0) {
00227                 WRITE_ERROR("Source district '" + myVehicleParameter->fromTaz + "' has no outgoing edges for '" + myVehicleParameter->id + "'!");
00228             } else {
00229                 myActiveRoute.push_back(fromTaz->getFollower(0));
00230             }
00231         }
00232         closeRoute();
00233         closeVehicle();
00234     }
00235     break;
00236     default:
00237         break;
00238     }
00239     // parse embedded vtype information
00240     if (myCurrentVType!=0&&element!=SUMO_TAG_VTYPE&&element!=SUMO_TAG_VTYPE__DEPRECATED) {
00241         SUMOVehicleParserHelper::parseVTypeEmbedded(*myCurrentVType, element, attrs);
00242         return;
00243     }
00244 }
00245 
00246 
00247 void
00248 MSRouteHandler::openVehicleTypeDistribution(const SUMOSAXAttributes& attrs) {
00249     bool ok = true;
00250     myCurrentVTypeDistributionID = attrs.getStringReporting(SUMO_ATTR_ID, 0, ok);
00251     if (ok) {
00252         myCurrentVTypeDistribution = new RandomDistributor<MSVehicleType*>();
00253         if (attrs.hasAttribute(SUMO_ATTR_VTYPES)||attrs.hasAttribute(SUMO_ATTR_VTYPES__DEPRECATED)) {
00254             std::string vTypes;
00255             if (!myHaveWarnedAboutDeprecatedVTypes&&attrs.hasAttribute(SUMO_ATTR_VTYPES__DEPRECATED)) {
00256                 myHaveWarnedAboutDeprecatedVTypes = true;
00257                 WRITE_WARNING("'" + toString(SUMO_ATTR_VTYPES__DEPRECATED) + "' is deprecated, please use '" + toString(SUMO_ATTR_VTYPES) + "' instead.");
00258                 vTypes = attrs.getStringReporting(SUMO_ATTR_VTYPES__DEPRECATED, myCurrentVTypeDistributionID.c_str(), ok);
00259             } else {
00260                 vTypes = attrs.getStringReporting(SUMO_ATTR_VTYPES, myCurrentVTypeDistributionID.c_str(), ok);
00261             }
00262             StringTokenizer st(vTypes);
00263             while (st.hasNext()) {
00264                 std::string vtypeID = st.next();
00265                 MSVehicleType* type = MSNet::getInstance()->getVehicleControl().getVType(vtypeID);
00266                 if (type==0) {
00267                     throw ProcessError("Unknown vtype '" + vtypeID + "' in distribution '" + myCurrentVTypeDistributionID + "'.");
00268                 }
00269                 myCurrentVTypeDistribution->add(type->getDefaultProbability(), type);
00270             }
00271         }
00272     }
00273 }
00274 
00275 
00276 void
00277 MSRouteHandler::closeVehicleTypeDistribution() {
00278     if (myCurrentVTypeDistribution != 0) {
00279         if (myCurrentVTypeDistribution->getOverallProb() == 0) {
00280             delete myCurrentVTypeDistribution;
00281             WRITE_ERROR("Vehicle type distribution '" + myCurrentVTypeDistributionID + "' is empty.");
00282         } else if (!MSNet::getInstance()->getVehicleControl().addVTypeDistribution(myCurrentVTypeDistributionID, myCurrentVTypeDistribution)) {
00283             delete myCurrentVTypeDistribution;
00284             WRITE_ERROR("Another vehicle type (or distribution) with the id '" + myCurrentVTypeDistributionID + "' exists.");
00285         }
00286         myCurrentVTypeDistribution = 0;
00287     }
00288 }
00289 
00290 
00291 void
00292 MSRouteHandler::openRoute(const SUMOSAXAttributes& attrs) {
00293     // check whether the id is really necessary
00294     std::string rid;
00295     if (myCurrentRouteDistribution != 0) {
00296         myActiveRouteID = myCurrentRouteDistributionID + "#" + toString(myCurrentRouteDistribution->getProbs().size()); // !!! document this
00297         rid =  "distribution '" + myCurrentRouteDistributionID + "'";
00298     } else if (myVehicleParameter!=0) {
00299         // ok, a vehicle is wrapping the route,
00300         //  we may use this vehicle's id as default
00301         myActiveRouteID = "!" + myVehicleParameter->id; // !!! document this
00302         if (attrs.hasAttribute(SUMO_ATTR_ID)) {
00303             WRITE_WARNING("Ids of internal routes are ignored (vehicle '" + myVehicleParameter->id + "').");
00304         }
00305     } else {
00306         bool ok = true;
00307         myActiveRouteID = attrs.getStringReporting(SUMO_ATTR_ID, 0, ok, false);
00308         if (!ok) {
00309             return;
00310         }
00311         rid = "'" + myActiveRouteID + "'";
00312     }
00313     if (myVehicleParameter!=0) { // have to do this here for nested route distributions
00314         rid =  "for vehicle '" + myVehicleParameter->id + "'";
00315     }
00316     bool ok = true;
00317     if (attrs.hasAttribute(SUMO_ATTR_EDGES)) {
00318         MSEdge::parseEdgesList(attrs.getStringReporting(SUMO_ATTR_EDGES, myActiveRouteID.c_str(), ok), myActiveRoute, rid);
00319     }
00320     myActiveRouteRefID = attrs.getOptStringReporting(SUMO_ATTR_REFID, myActiveRouteID.c_str(), ok, "");
00321     if (attrs.hasAttribute(SUMO_ATTR_REFID__DEPRECATED)) {
00322         myActiveRouteRefID = attrs.getOptStringReporting(SUMO_ATTR_REFID__DEPRECATED, myActiveRouteID.c_str(), ok, "");
00323         if (!myHaveWarnedAboutDeprecatedRefID) {
00324             myHaveWarnedAboutDeprecatedRefID = true;
00325             WRITE_WARNING("'" + toString(SUMO_ATTR_REFID__DEPRECATED) + "' is deprecated, please use '" + toString(SUMO_ATTR_REFID) + "' instead.");
00326         }
00327     }
00328     if (myActiveRouteRefID != "" && MSRoute::dictionary(myActiveRouteRefID) == 0) {
00329         WRITE_ERROR("Invalid reference to route '" + myActiveRouteRefID + "' in route " + rid + ".");
00330     }
00331     myActiveRouteProbability = attrs.getOptSUMORealReporting(SUMO_ATTR_PROB, myActiveRouteID.c_str(), ok, DEFAULT_VEH_PROB);
00332     myActiveRouteColor = attrs.hasAttribute(SUMO_ATTR_COLOR) ? RGBColor::parseColorReporting(attrs.getString(SUMO_ATTR_COLOR), attrs.getObjectType(),  myActiveRouteID.c_str(), true, ok) : RGBColor::getDefaultColor();
00333 }
00334 
00335 
00336 void
00337 MSRouteHandler::myEndElement(int element) throw(ProcessError) {
00338     switch (element) {
00339     case SUMO_TAG_ROUTE:
00340         closeRoute();
00341         break;
00342     case SUMO_TAG_PERSON:
00343         closePerson();
00344         delete myVehicleParameter;
00345         myVehicleParameter = 0;
00346         break;
00347     case SUMO_TAG_VEHICLE:
00348         if (myVehicleParameter->repetitionNumber>0) {
00349             myVehicleParameter->repetitionNumber++; // for backwards compatibility
00350             // it is a flow, thus no break here
00351         } else {
00352             closeVehicle();
00353             delete myVehicleParameter;
00354             myVehicleParameter = 0;
00355             break;
00356         }
00357     case SUMO_TAG_FLOW:
00358         closeFlow();
00359         break;
00360     case SUMO_TAG_VTYPE_DISTRIBUTION__DEPRECATED:
00361     case SUMO_TAG_VTYPE_DISTRIBUTION:
00362         closeVehicleTypeDistribution();
00363         break;
00364     case SUMO_TAG_ROUTE_DISTRIBUTION:
00365         closeRouteDistribution();
00366         break;
00367     case SUMO_TAG_VTYPE__DEPRECATED:
00368     case SUMO_TAG_VTYPE: {
00369         SUMOVehicleParserHelper::closeVTypeParsing(*myCurrentVType);
00370         MSVehicleType* vehType = MSVehicleType::build(*myCurrentVType);
00371         delete myCurrentVType;
00372         myCurrentVType = 0;
00373         if (!MSNet::getInstance()->getVehicleControl().addVType(vehType)) {
00374             std::string id = vehType->getID();
00375             delete vehType;
00376 #ifdef HAVE_MESOSIM
00377             if (!MSGlobals::gStateLoaded) {
00378 #endif
00379                 throw ProcessError("Another vehicle type (or distribution) with the id '" + id + "' exists.");
00380 #ifdef HAVE_MESOSIM
00381             }
00382 #endif
00383         } else {
00384             if (myCurrentVTypeDistribution != 0) {
00385                 myCurrentVTypeDistribution->add(vehType->getDefaultProbability(), vehType);
00386             }
00387         }
00388     }
00389     break;
00390     default:
00391         break;
00392     }
00393 }
00394 
00395 
00396 void
00397 MSRouteHandler::closeRoute() throw(ProcessError) {
00398     if (myActiveRoute.size()==0) {
00399         if (myActiveRouteRefID != "" && myCurrentRouteDistribution != 0) {
00400             myCurrentRouteDistribution->add(myActiveRouteProbability, MSRoute::dictionary(myActiveRouteRefID));
00401             myActiveRouteID = "";
00402             myActiveRouteRefID = "";
00403             return;
00404         }
00405         if (myVehicleParameter!=0) {
00406             throw ProcessError("Vehicle's '" + myVehicleParameter->id + "' route has no edges.");
00407         } else {
00408             throw ProcessError("Route '" + myActiveRouteID + "' has no edges.");
00409         }
00410     }
00411     MSRoute* route = new MSRoute(myActiveRouteID, myActiveRoute,
00412                                  myVehicleParameter==0||myVehicleParameter->repetitionNumber>=1,
00413                                  myActiveRouteColor, myActiveRouteStops);
00414     myActiveRoute.clear();
00415     if (!MSRoute::dictionary(myActiveRouteID, route)) {
00416         delete route;
00417 #ifdef HAVE_MESOSIM
00418         if (!MSGlobals::gStateLoaded) {
00419 #endif
00420             if (myVehicleParameter!=0) {
00421                 if (MSNet::getInstance()->getVehicleControl().getVehicle(myVehicleParameter->id)==0) {
00422                     throw ProcessError("Another route for vehicle '" + myVehicleParameter->id + "' exists.");
00423                 } else {
00424                     throw ProcessError("A vehicle with id '" + myVehicleParameter->id + "' already exists.");
00425                 }
00426             } else {
00427                 throw ProcessError("Another route (or distribution) with the id '" + myActiveRouteID + "' exists.");
00428             }
00429 #ifdef HAVE_MESOSIM
00430         }
00431 #endif
00432     } else {
00433         if (myCurrentRouteDistribution != 0) {
00434             myCurrentRouteDistribution->add(myActiveRouteProbability, route);
00435         }
00436     }
00437     myActiveRouteID = "";
00438     myActiveRouteStops.clear();
00439 }
00440 
00441 
00442 void
00443 MSRouteHandler::openRouteDistribution(const SUMOSAXAttributes& attrs) {
00444     // check whether the id is really necessary
00445     bool ok = true;
00446     if (myVehicleParameter!=0) {
00447         // ok, a vehicle is wrapping the route,
00448         //  we may use this vehicle's id as default
00449         myCurrentRouteDistributionID = "!" + myVehicleParameter->id; // !!! document this
00450     } else {
00451         myCurrentRouteDistributionID = attrs.getStringReporting(SUMO_ATTR_ID, 0, ok);
00452         if (!ok) {
00453             return;
00454         }
00455     }
00456     myCurrentRouteDistribution = new RandomDistributor<const MSRoute*>();
00457     if (attrs.hasAttribute(SUMO_ATTR_ROUTES)) {
00458         bool ok = true;
00459         StringTokenizer st(attrs.getStringReporting(SUMO_ATTR_ROUTES, myCurrentRouteDistributionID.c_str(), ok));
00460         while (st.hasNext()) {
00461             std::string routeID = st.next();
00462             const MSRoute* route = MSRoute::dictionary(routeID);
00463             if (route==0) {
00464                 throw ProcessError("Unknown route '" + routeID + "' in distribution '" + myCurrentRouteDistributionID + "'.");
00465             }
00466             myCurrentRouteDistribution->add(1., route, false);
00467         }
00468     }
00469 }
00470 
00471 
00472 void
00473 MSRouteHandler::closeRouteDistribution() {
00474     if (myCurrentRouteDistribution != 0) {
00475         if (myCurrentRouteDistribution->getOverallProb() == 0) {
00476             delete myCurrentRouteDistribution;
00477             WRITE_ERROR("Route distribution '" + myCurrentRouteDistributionID + "' is empty.");
00478         } else if (!MSRoute::dictionary(myCurrentRouteDistributionID, myCurrentRouteDistribution)) {
00479             delete myCurrentRouteDistribution;
00480             WRITE_ERROR("Another route (or distribution) with the id '" + myCurrentRouteDistributionID + "' exists.");
00481         }
00482         myCurrentRouteDistribution = 0;
00483     }
00484 }
00485 
00486 
00487 void
00488 MSRouteHandler::closeVehicle() throw(ProcessError) {
00489     // get nested route
00490     const MSRoute* route = MSRoute::dictionary("!" + myVehicleParameter->id);
00491     MSVehicleControl& vehControl = MSNet::getInstance()->getVehicleControl();
00492     if (myVehicleParameter->departProcedure == DEPART_GIVEN) {
00493         // let's check whether this vehicle had to depart before the simulation starts
00494         if (!checkLastDepart() || myVehicleParameter->depart<string2time(OptionsCont::getOptions().getString("begin"))) {
00495             if (route!=0) {
00496                 route->addReference();
00497                 route->release();
00498             }
00499             return;
00500         }
00501     }
00502     // get the vehicle's type
00503     MSVehicleType* vtype = 0;
00504     if (myVehicleParameter->vtypeid!="") {
00505         vtype = vehControl.getVType(myVehicleParameter->vtypeid);
00506         if (vtype==0) {
00507             throw ProcessError("The vehicle type '" + myVehicleParameter->vtypeid + "' for vehicle '" + myVehicleParameter->id + "' is not known.");
00508         }
00509     } else {
00510         // there should be one (at least the default one)
00511         vtype = vehControl.getVType();
00512     }
00513     if (route==0) {
00514         // if there is no nested route, try via the (hopefully) given route-id
00515         route = MSRoute::dictionary(myVehicleParameter->routeid);
00516     }
00517     if (route==0) {
00518         // nothing found? -> error
00519         if (myVehicleParameter->routeid!="") {
00520             throw ProcessError("The route '" + myVehicleParameter->routeid + "' for vehicle '" + myVehicleParameter->id + "' is not known.");
00521         } else {
00522             throw ProcessError("Vehicle '" + myVehicleParameter->id + "' has no route.");
00523         }
00524     }
00525     myActiveRouteID = "";
00526 
00527     // try to build the vehicle
00528     SUMOVehicle* vehicle = 0;
00529     if (vehControl.getVehicle(myVehicleParameter->id)==0) {
00530         vehicle = vehControl.buildVehicle(myVehicleParameter, route, vtype);
00531         // maybe we do not want this vehicle to be inserted due to scaling
00532         if (myScale < 0 || vehControl.isInQuota(myScale)) {
00533             // add the vehicle to the vehicle control
00534             vehControl.addVehicle(myVehicleParameter->id, vehicle);
00535             if (myVehicleParameter->departProcedure == DEPART_TRIGGERED) {
00536                 vehControl.addWaiting(*route->begin(), vehicle);
00537                 vehControl.registerOneWaitingForPerson();
00538             }
00539             myVehicleParameter = 0;
00540         } else {
00541             vehControl.deleteVehicle(vehicle);
00542             myVehicleParameter = 0;
00543             vehicle = 0;
00544         }
00545     } else {
00546         // strange: another vehicle with the same id already exists
00547 #ifdef HAVE_MESOSIM
00548         if (!MSGlobals::gStateLoaded) {
00549 #endif
00550             // and was not loaded while loading a simulation state
00551             // -> error
00552             throw ProcessError("Another vehicle with the id '" + myVehicleParameter->id + "' exists.");
00553 #ifdef HAVE_MESOSIM
00554         } else {
00555             // ok, it seems to be loaded previously while loading a simulation state
00556             vehicle = 0;
00557         }
00558 #endif
00559     }
00560     // check whether the vehicle shall be added directly to the network or
00561     //  shall stay in the internal buffer
00562     if (vehicle!=0) {
00563         if (vehicle->getParameter().departProcedure == DEPART_GIVEN) {
00564             MSNet::getInstance()->getInsertionControl().add(vehicle);
00565         }
00566     }
00567 }
00568 
00569 
00570 void
00571 MSRouteHandler::closePerson() throw(ProcessError) {
00572     if (myActivePlan->size()==0) {
00573         throw ProcessError("Person '" + myVehicleParameter->id + "' has no plan.");
00574     }
00575     MSPerson* person = new MSPerson(myVehicleParameter, myActivePlan);
00576     if (checkLastDepart() && MSNet::getInstance()->getPersonControl().add(myVehicleParameter->id, person)) {
00577         MSNet::getInstance()->getPersonControl().setArrival(myVehicleParameter->depart, person);
00578     } else {
00579         delete person;
00580     }
00581     myVehicleParameter = 0;
00582     myActivePlan = 0;
00583 }
00584 
00585 
00586 void
00587 MSRouteHandler::closeFlow() throw(ProcessError) {
00588     // let's check whether vehicles had to depart before the simulation starts
00589     myVehicleParameter->repetitionsDone = 0;
00590     SUMOTime offsetToBegin = string2time(OptionsCont::getOptions().getString("begin")) - myVehicleParameter->depart;
00591     while (myVehicleParameter->repetitionsDone * myVehicleParameter->repetitionOffset < offsetToBegin) {
00592         myVehicleParameter->repetitionsDone++;
00593         if (myVehicleParameter->repetitionsDone == myVehicleParameter->repetitionNumber) {
00594             return;
00595         }
00596     }
00597     if (MSNet::getInstance()->getVehicleControl().getVType(myVehicleParameter->vtypeid)==0) {
00598         throw ProcessError("The vehicle type '" + myVehicleParameter->vtypeid + "' for vehicle '" + myVehicleParameter->id + "' is not known.");
00599     }
00600     if (MSRoute::dictionary("!" + myVehicleParameter->id)==0) {
00601         // if not, try via the (hopefully) given route-id
00602         if (MSRoute::dictionary(myVehicleParameter->routeid) == 0) {
00603             if (myVehicleParameter->routeid!="") {
00604                 throw ProcessError("The route '" + myVehicleParameter->routeid + "' for vehicle '" + myVehicleParameter->id + "' is not known.");
00605             } else {
00606                 throw ProcessError("Vehicle '" + myVehicleParameter->id + "' has no route.");
00607             }
00608         }
00609     } else {
00610         myVehicleParameter->routeid = "!" + myVehicleParameter->id;
00611     }
00612     myActiveRouteID = "";
00613 
00614     // check whether the vehicle shall be added directly to the network or
00615     //  shall stay in the internal buffer
00616     if (checkLastDepart()) {
00617         MSNet::getInstance()->getInsertionControl().add(myVehicleParameter);
00618     }
00619     myVehicleParameter = 0;
00620 }
00621 
00622 bool
00623 MSRouteHandler::checkStopPos(SUMOReal& startPos, SUMOReal& endPos, const SUMOReal laneLength,
00624                              const SUMOReal minLength, const bool friendlyPos) {
00625     if (minLength > laneLength) {
00626         return false;
00627     }
00628     if (startPos < 0) {
00629         startPos += laneLength;
00630     }
00631     if (endPos < 0) {
00632         endPos += laneLength;
00633     }
00634     if (endPos < minLength || endPos > laneLength) {
00635         if (!friendlyPos) {
00636             return false;
00637         }
00638         if (endPos < minLength) {
00639             endPos = minLength;
00640         }
00641         if (endPos > laneLength) {
00642             endPos = laneLength;
00643         }
00644     }
00645     if (startPos < 0 || startPos > endPos - minLength) {
00646         if (!friendlyPos) {
00647             return false;
00648         }
00649         if (startPos < 0) {
00650             startPos = 0;
00651         }
00652         if (startPos > endPos - minLength) {
00653             startPos = endPos - minLength;
00654         }
00655     }
00656     return true;
00657 }
00658 
00659 
00660 void
00661 MSRouteHandler::addStop(const SUMOSAXAttributes& attrs) throw(ProcessError) {
00662     bool ok = true;
00663     std::string errorSuffix;
00664     if (myActiveRouteID != "") {
00665         errorSuffix = " in route '" + myActiveRouteID + "'.";
00666     } else if (myActivePlan) {
00667         errorSuffix = " in person '" + myVehicleParameter->id + "'.";
00668     } else {
00669         errorSuffix = " in vehicle '" + myVehicleParameter->id + "'.";
00670     }
00671     SUMOVehicleParameter::Stop stop;
00672     // try to parse the assigned bus stop
00673     if (attrs.hasAttribute(SUMO_ATTR_BUS_STOP__DEPRECATED)) {
00674         stop.busstop = attrs.getStringReporting(SUMO_ATTR_BUS_STOP__DEPRECATED, 0, ok);
00675         if (!myHaveWarnedAboutDeprecatedBusStop) {
00676             myHaveWarnedAboutDeprecatedBusStop = true;
00677             WRITE_WARNING("'bus_stop' is deprecated, please use 'busStop' instead.");
00678         }
00679     } else {
00680         stop.busstop = attrs.getOptStringReporting(SUMO_ATTR_BUS_STOP, 0, ok, "");
00681     }
00682     if (stop.busstop!="") {
00683         // ok, we have obviously a bus stop
00684         MSBusStop* bs = MSNet::getInstance()->getBusStop(stop.busstop);
00685         if (bs!=0) {
00686             const MSLane& l = bs->getLane();
00687             stop.lane = l.getID();
00688             stop.endPos = bs->getEndLanePosition();
00689             stop.startPos = bs->getBeginLanePosition();
00690         } else {
00691             WRITE_ERROR("The bus stop '" + stop.busstop + "' is not known" + errorSuffix);
00692             return;
00693         }
00694     } else {
00695         // no, the lane and the position should be given
00696         // get the lane
00697         stop.lane = attrs.getOptStringReporting(SUMO_ATTR_LANE, 0, ok, "");
00698         if (ok && stop.lane!="") {
00699             if (MSLane::dictionary(stop.lane)==0) {
00700                 WRITE_ERROR("The lane '" + stop.lane + "' for a stop is not known" + errorSuffix);
00701                 return;
00702             }
00703         } else {
00704             WRITE_ERROR("A stop must be placed on a bus stop or a lane" + errorSuffix);
00705             return;
00706         }
00707         if (myActivePlan &&
00708                 !myActivePlan->empty() &&
00709                 &myActivePlan->back()->getDestination() != &MSLane::dictionary(stop.lane)->getEdge()) {
00710             throw ProcessError("Disconnected plan for person '" + myVehicleParameter->id + "' (" + MSLane::dictionary(stop.lane)->getEdge().getID() + "!=" + myActivePlan->back()->getDestination().getID() + ").");
00711         }
00712         stop.endPos = attrs.getOptSUMORealReporting(SUMO_ATTR_ENDPOS, 0, ok, MSLane::dictionary(stop.lane)->getLength());
00713         if (attrs.hasAttribute(SUMO_ATTR_POSITION)) {
00714             WRITE_WARNING("Deprecated attribute 'pos' in description of stop" + errorSuffix);
00715             stop.endPos = attrs.getOptSUMORealReporting(SUMO_ATTR_POSITION, 0, ok, stop.endPos);
00716         }
00717         stop.startPos = attrs.getOptSUMORealReporting(SUMO_ATTR_STARTPOS, 0, ok, stop.endPos - 2 * POSITION_EPS);
00718         if (attrs.hasAttribute(SUMO_ATTR_FRIENDLY_POS__DEPRECATED)&&!myHaveWarnedAboutDeprecatedFriendlyPos) {
00719             myHaveWarnedAboutDeprecatedFriendlyPos = true;
00720             WRITE_WARNING("'" + toString(SUMO_ATTR_FRIENDLY_POS__DEPRECATED) + "' is deprecated, use '" + toString(SUMO_ATTR_FRIENDLY_POS) + "' instead.");
00721         }
00722         bool friendlyPos = attrs.hasAttribute(SUMO_ATTR_FRIENDLY_POS__DEPRECATED)
00723                            ? attrs.getOptBoolReporting(SUMO_ATTR_FRIENDLY_POS__DEPRECATED, 0, ok, false)
00724                            : attrs.getOptBoolReporting(SUMO_ATTR_FRIENDLY_POS, 0, ok, false);
00725         if (!ok || !checkStopPos(stop.startPos, stop.endPos, MSLane::dictionary(stop.lane)->getLength(), POSITION_EPS, friendlyPos)) {
00726             WRITE_ERROR("Invalid start or end position for stop" + errorSuffix);
00727             return;
00728         }
00729     }
00730 
00731     // get the standing duration
00732     if (!attrs.hasAttribute(SUMO_ATTR_DURATION) && !attrs.hasAttribute(SUMO_ATTR_UNTIL)) {
00733         stop.triggered = attrs.getOptBoolReporting(SUMO_ATTR_TRIGGERED, 0, ok, true);
00734         stop.duration = -1;
00735         stop.until = -1;
00736     } else {
00737         stop.duration = attrs.getOptSUMOTimeReporting(SUMO_ATTR_DURATION, 0, ok, -1);
00738         stop.until = attrs.getOptSUMOTimeReporting(SUMO_ATTR_UNTIL, 0, ok, -1);
00739         if (!ok || (stop.duration<0&&stop.until<0)) {
00740             WRITE_ERROR("Invalid duration or end time is given for a stop" + errorSuffix);
00741             return;
00742         }
00743         stop.triggered = attrs.getOptBoolReporting(SUMO_ATTR_TRIGGERED, 0, ok, false);
00744     }
00745     stop.parking = attrs.getOptBoolReporting(SUMO_ATTR_PARKING, 0, ok, stop.triggered);
00746     if (!ok) {
00747         WRITE_ERROR("Invalid bool for 'triggered' or 'parking' for stop" + errorSuffix);
00748         return;
00749     }
00750     const std::string idx = attrs.getOptStringReporting(SUMO_ATTR_INDEX, 0, ok, "end");
00751     if (idx == "end") {
00752         stop.index = STOP_INDEX_END;
00753     } else if (idx == "fit") {
00754         stop.index = STOP_INDEX_FIT;
00755     } else {
00756         stop.index = attrs.getIntReporting(SUMO_ATTR_INDEX, 0, ok);
00757         if (!ok || stop.index < 0) {
00758             WRITE_ERROR("Invalid 'index' for stop" + errorSuffix);
00759             return;
00760         }
00761     }
00762     if (myActiveRouteID != "") {
00763         myActiveRouteStops.push_back(stop);
00764     } else if (myActivePlan) {
00765         myActivePlan->push_back(new MSPerson::MSPersonStage_Waiting(MSLane::dictionary(stop.lane)->getEdge(), stop.duration, stop.until));
00766     } else {
00767         myVehicleParameter->stops.push_back(stop);
00768     }
00769 }
00770 
00771 
00772 /****************************************************************************/
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Defines