|
SUMO - Simulation of Urban MObility
|
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 /****************************************************************************/