SUMO - Simulation of Urban MObility
NIXMLConnectionsHandler.cpp
Go to the documentation of this file.
00001 /****************************************************************************/
00010 // Importer for edge connections stored in XML
00011 /****************************************************************************/
00012 // SUMO, Simulation of Urban MObility; see http://sumo.sourceforge.net/
00013 // Copyright (C) 2001-2012 DLR (http://www.dlr.de/) and contributors
00014 /****************************************************************************/
00015 //
00016 //   This file is part of SUMO.
00017 //   SUMO is free software: you can redistribute it and/or modify
00018 //   it under the terms of the GNU General Public License as published by
00019 //   the Free Software Foundation, either version 3 of the License, or
00020 //   (at your option) any later version.
00021 //
00022 /****************************************************************************/
00023 
00024 
00025 // ===========================================================================
00026 // included modules
00027 // ===========================================================================
00028 #ifdef _MSC_VER
00029 #include <windows_config.h>
00030 #else
00031 #include <config.h>
00032 #endif
00033 
00034 #include <string>
00035 #include <iostream>
00036 #include <xercesc/sax/HandlerBase.hpp>
00037 #include <xercesc/sax/AttributeList.hpp>
00038 #include <xercesc/sax/SAXParseException.hpp>
00039 #include <xercesc/sax/SAXException.hpp>
00040 #include "NIXMLConnectionsHandler.h"
00041 #include <netbuild/NBEdge.h>
00042 #include <netbuild/NBEdgeCont.h>
00043 #include <netbuild/NBNode.h>
00044 #include <utils/common/StringTokenizer.h>
00045 #include <utils/xml/SUMOSAXHandler.h>
00046 #include <utils/xml/SUMOXMLDefinitions.h>
00047 #include <utils/common/ToString.h>
00048 #include <utils/common/TplConvert.h>
00049 #include <utils/common/TplConvertSec.h>
00050 #include <utils/common/UtilExceptions.h>
00051 #include <utils/common/MsgHandler.h>
00052 #include <utils/options/OptionsCont.h>
00053 
00054 #ifdef CHECK_MEMORY_LEAKS
00055 #include <foreign/nvwa/debug_new.h>
00056 #endif // CHECK_MEMORY_LEAKS
00057 
00058 
00059 // ===========================================================================
00060 // method definitions
00061 // ===========================================================================
00062 NIXMLConnectionsHandler::NIXMLConnectionsHandler(NBEdgeCont& ec) :
00063     SUMOSAXHandler("xml-connection-description"),
00064     myEdgeCont(ec),
00065     myHaveWarnedAboutDeprecatedLanes(false),
00066     myErrorMsgHandler(OptionsCont::getOptions().getBool("ignore-errors.connections") ?
00067                       MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance()) {}
00068 
00069 
00070 NIXMLConnectionsHandler::~NIXMLConnectionsHandler() {}
00071 
00072 
00073 void
00074 NIXMLConnectionsHandler::myStartElement(int element,
00075                                         const SUMOSAXAttributes& attrs) {
00076     if (element == SUMO_TAG_DELETE) {
00077         bool ok = true;
00078         std::string from = attrs.getStringReporting(SUMO_ATTR_FROM, 0, ok);
00079         std::string to = attrs.getStringReporting(SUMO_ATTR_TO, 0, ok);
00080         if (!ok) {
00081             return;
00082         }
00083         // these connections were removed when the edge was deleted
00084         if (myEdgeCont.wasRemoved(from) || myEdgeCont.wasRemoved(to)) {
00085             return;
00086         }
00087         NBEdge* fromEdge = myEdgeCont.retrieve(from);
00088         NBEdge* toEdge = myEdgeCont.retrieve(to);
00089         if (fromEdge == 0) {
00090             myErrorMsgHandler->inform("The connection-source edge '" + from + "' to reset is not known.");
00091             return;
00092         }
00093         if (toEdge == 0) {
00094             myErrorMsgHandler->inform("The connection-destination edge '" + to + "' to reset is not known.");
00095             return;
00096         }
00097         if (!fromEdge->isConnectedTo(toEdge)) {
00098             WRITE_WARNING("Target edge '" + toEdge->getID() + "' is not connected with '" + fromEdge->getID() + "'; the connection cannot be reset.");
00099             return;
00100         }
00101         int fromLane = -1; // Assume all lanes are to be reset.
00102         int toLane = -1;
00103         if (attrs.hasAttribute(SUMO_ATTR_LANE)
00104                 || attrs.hasAttribute(SUMO_ATTR_FROM_LANE)
00105                 || attrs.hasAttribute(SUMO_ATTR_TO_LANE)) {
00106             if (!parseLaneInfo(attrs, fromEdge, toEdge, &fromLane, &toLane)) {
00107                 return;
00108             }
00109             // we could be trying to reset a connection loaded from a sumo net and which has become obsolete.
00110             // In this case it's ok to encounter invalid lance indices
00111             if (!fromEdge->hasConnectionTo(toEdge, toLane)) {
00112                 WRITE_WARNING("Edge '" + fromEdge->getID() + "' has no connection to lane " + toString(toLane) + " of edge '" + toEdge->getID() + "'; the connection cannot be reset.");
00113             }
00114         }
00115         fromEdge->removeFromConnections(toEdge, fromLane, toLane);
00116     }
00117 
00118     if (element == SUMO_TAG_CONNECTION) {
00119         bool ok = true;
00120         std::string from = attrs.getStringReporting(SUMO_ATTR_FROM, "connection", ok);
00121         std::string to = attrs.getOptStringReporting(SUMO_ATTR_TO, "connection", ok, "");
00122         if (!ok || myEdgeCont.wasIgnored(from) || myEdgeCont.wasIgnored(to)) {
00123             return;
00124         }
00125         // extract edges
00126         NBEdge* fromEdge = myEdgeCont.retrieve(from);
00127         NBEdge* toEdge = to.length() != 0 ? myEdgeCont.retrieve(to) : 0;
00128         // check whether they are valid
00129         if (fromEdge == 0) {
00130             myErrorMsgHandler->inform("The connection-source edge '" + from + "' is not known.");
00131             return;
00132         }
00133         if (toEdge == 0 && to.length() != 0) {
00134             myErrorMsgHandler->inform("The connection-destination edge '" + to + "' is not known.");
00135             return;
00136         }
00137         // parse optional lane information
00138         if (attrs.hasAttribute(SUMO_ATTR_LANE) || attrs.hasAttribute(SUMO_ATTR_FROM_LANE) || attrs.hasAttribute(SUMO_ATTR_TO_LANE)) {
00139             parseLaneBound(attrs, fromEdge, toEdge);
00140         } else {
00141             fromEdge->addEdge2EdgeConnection(toEdge);
00142         }
00143     }
00144     if (element == SUMO_TAG_PROHIBITION) {
00145         bool ok = true;
00146         std::string prohibitor = attrs.getOptStringReporting(SUMO_ATTR_PROHIBITOR, 0, ok, "");
00147         std::string prohibited = attrs.getOptStringReporting(SUMO_ATTR_PROHIBITED, 0, ok, "");
00148         if (!ok) {
00149             return;
00150         }
00151         NBConnection prohibitorC = parseConnection("prohibitor", prohibitor);
00152         NBConnection prohibitedC = parseConnection("prohibited", prohibited);
00153         if (prohibitorC.getFrom() == 0 || prohibitedC.getFrom() == 0) {
00154             // something failed
00155             return;
00156         }
00157         NBNode* n = prohibitorC.getFrom()->getToNode();
00158         n->addSortedLinkFoes(prohibitorC, prohibitedC);
00159     }
00160 }
00161 
00162 
00163 NBConnection
00164 NIXMLConnectionsHandler::parseConnection(const std::string& defRole, const std::string& def) {
00165     // split from/to
00166     size_t div = def.find("->");
00167     if (div == std::string::npos) {
00168         myErrorMsgHandler->inform("Missing connection divider in " + defRole + " '" + def + "'");
00169         return NBConnection(0, 0);
00170     }
00171     std::string fromDef = def.substr(0, div);
00172     std::string toDef = def.substr(div + 2);
00173 
00174     // retrieve the edges
00175     // check whether the definition includes a lane information (do not process it)
00176     if (fromDef.find('_') != std::string::npos) {
00177         fromDef = fromDef.substr(0, fromDef.find('_'));
00178     }
00179     if (toDef.find('_') != std::string::npos) {
00180         toDef = toDef.substr(0, toDef.find('_'));
00181     }
00182     // retrieve them now
00183     NBEdge* fromE = myEdgeCont.retrieve(fromDef);
00184     NBEdge* toE = myEdgeCont.retrieve(toDef);
00185     // check
00186     if (fromE == 0) {
00187         myErrorMsgHandler->inform("Could not find edge '" + fromDef + "' in " + defRole + " '" + def + "'");
00188         return NBConnection(0, 0);
00189     }
00190     if (toE == 0) {
00191         myErrorMsgHandler->inform("Could not find edge '" + toDef + "' in " + defRole + " '" + def + "'");
00192         return NBConnection(0, 0);
00193     }
00194     return NBConnection(fromE, toE);
00195 }
00196 
00197 
00198 void
00199 NIXMLConnectionsHandler::parseLaneBound(const SUMOSAXAttributes& attrs, NBEdge* from, NBEdge* to) {
00200     if (to == 0) {
00201         // do nothing if it's a dead end
00202         return;
00203     }
00204     bool ok = true;
00205     const bool mayDefinitelyPass = attrs.getOptBoolReporting(SUMO_ATTR_PASS, 0, ok, false);
00206     if (!ok) {
00207         return;
00208     }
00209     // get the begin and the end lane
00210     int fromLane;
00211     int toLane;
00212     try {
00213         if (!parseLaneInfo(attrs, from, to, &fromLane, &toLane)) {
00214             return;
00215         }
00216         if (!validateLaneInfo(false /* canLanesBeNegative */, from, to, fromLane, toLane)) {
00217             return;
00218         }
00219         if (from->hasConnectionTo(to, toLane)) {
00220             WRITE_WARNING("Target lane '" + to->getLaneID(toLane) + "' is already connected from '" + from->getID() + "'.");
00221         }
00222         if (!from->addLane2LaneConnection(fromLane, to, toLane, NBEdge::L2L_USER, true, mayDefinitelyPass)) {
00223             NBEdge* nFrom = from;
00224             bool toNext = true;
00225             do {
00226                 if (nFrom->getToNode()->getOutgoingEdges().size() != 1) {
00227                     toNext = false;
00228                     break;
00229                 }
00230                 NBEdge* t = nFrom->getToNode()->getOutgoingEdges()[0];
00231                 if (t->getID().substr(0, t->getID().find('/')) != nFrom->getID().substr(0, nFrom->getID().find('/'))) {
00232                     toNext = false;
00233                     break;
00234                 }
00235                 if (toNext) {
00236                     nFrom = t;
00237                 }
00238             } while (toNext);
00239             if (nFrom == 0 || !nFrom->addLane2LaneConnection(fromLane, to, toLane, NBEdge::L2L_USER, false, mayDefinitelyPass)) {
00240                 WRITE_WARNING("Could not set loaded connection from '" + from->getLaneID(fromLane) +
00241                               "' to '" + to->getLaneID(toLane) + "'.");
00242             } else {
00243                 from = nFrom;
00244             }
00245         }
00246     } catch (NumberFormatException&) {
00247         myErrorMsgHandler->inform("At least one of the defined lanes was not numeric");
00248     }
00249     //
00250     bool keepUncontrolled = attrs.getOptBoolReporting(SUMO_ATTR_UNCONTROLLED, 0, ok, false);
00251     if (keepUncontrolled) {
00252         from->disableConnection4TLS(fromLane, to, toLane);
00253     }
00254 }
00255 
00256 bool
00257 NIXMLConnectionsHandler::parseLaneInfo(const SUMOSAXAttributes& attributes, NBEdge* fromEdge, NBEdge* toEdge,
00258                                        int* fromLane, int* toLane) {
00259     if (attributes.hasAttribute(SUMO_ATTR_LANE)) {
00260         return parseDeprecatedLaneDefinition(attributes, fromEdge, toEdge, fromLane, toLane);
00261     } else {
00262         return parseLaneDefinition(attributes, fromLane, toLane);
00263     }
00264 }
00265 
00266 
00267 inline bool
00268 NIXMLConnectionsHandler::parseDeprecatedLaneDefinition(const SUMOSAXAttributes& attributes,
00269         NBEdge* from, NBEdge* to,
00270         int* fromLane, int* toLane) {
00271     bool ok = true;
00272     if (!myHaveWarnedAboutDeprecatedLanes) {
00273         myHaveWarnedAboutDeprecatedLanes = true;
00274         WRITE_WARNING("'" + toString(SUMO_ATTR_LANE) + "' is deprecated, please use '" +
00275                       toString(SUMO_ATTR_FROM_LANE) + "' and '" + toString(SUMO_ATTR_TO_LANE) +
00276                       "' instead.");
00277     }
00278 
00279     std::string laneConn = attributes.getStringReporting(SUMO_ATTR_LANE, 0, ok);
00280     StringTokenizer st(laneConn, ':');
00281     if (!ok || st.size() != 2) {
00282         myErrorMsgHandler->inform("Invalid lane to lane connection from '" +
00283                                   from->getID() + "' to '" + to->getID() + "'.");
00284         return false; // There was an error.
00285     }
00286 
00287     *fromLane = TplConvertSec<char>::_2intSec(st.next().c_str(), -1);
00288     *toLane = TplConvertSec<char>::_2intSec(st.next().c_str(), -1);
00289 
00290     return true; // We succeeded.
00291 }
00292 
00293 
00294 inline bool
00295 NIXMLConnectionsHandler::parseLaneDefinition(const SUMOSAXAttributes& attributes,
00296         int* fromLane,
00297         int* toLane) {
00298     bool ok = true;
00299     *fromLane = attributes.getIntReporting(SUMO_ATTR_FROM_LANE, 0, ok);
00300     *toLane = attributes.getIntReporting(SUMO_ATTR_TO_LANE, 0, ok);
00301     return ok;
00302 }
00303 
00304 
00305 bool
00306 NIXMLConnectionsHandler::validateLaneInfo(bool canLanesBeNegative, NBEdge* fromEdge, NBEdge* toEdge, int fromLane, int toLane) {
00307     if ((!canLanesBeNegative && fromLane < 0) ||
00308             static_cast<unsigned int>(fromLane) >= fromEdge->getNumLanes()) {
00309         myErrorMsgHandler->inform("Invalid value '" + toString(fromLane) +
00310                                   "' for " + toString(SUMO_ATTR_FROM_LANE) + " in connection from '" +
00311                                   fromEdge->getID() + "' to '" + toEdge->getID() + "'.");
00312         return false;
00313     }
00314     if ((!canLanesBeNegative && toLane < 0) ||
00315             static_cast<unsigned int>(toLane) >= toEdge->getNumLanes()) {
00316         myErrorMsgHandler->inform("Invalid value '" + toString(toLane) +
00317                                   "' for " + toString(SUMO_ATTR_TO_LANE) + " in connection from '" +
00318                                   fromEdge->getID() + "' to '" + toEdge->getID() + "'.");
00319         return false;
00320     }
00321     return true;
00322 }
00323 
00324 /****************************************************************************/
00325 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Defines