SUMO - Simulation of Urban MObility

NIImporter_SUMO.cpp

Go to the documentation of this file.
00001 /****************************************************************************/
00007 // Importer for networks stored in SUMO format
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 #include <string>
00030 #include <utils/common/UtilExceptions.h>
00031 #include <utils/common/TplConvert.h>
00032 #include <utils/common/MsgHandler.h>
00033 #include <utils/common/StringTokenizer.h>
00034 #include <utils/common/FileHelpers.h>
00035 #include <utils/common/ToString.h>
00036 #include <utils/common/TplConvertSec.h>
00037 #include <utils/xml/SUMOXMLDefinitions.h>
00038 #include <utils/xml/SUMOSAXHandler.h>
00039 #include <utils/xml/XMLSubSys.h>
00040 #include <utils/geom/GeoConvHelper.h>
00041 #include <utils/geom/GeomConvHelper.h>
00042 #include <utils/options/OptionsCont.h>
00043 #include <netbuild/NBEdge.h>
00044 #include <netbuild/NBEdgeCont.h>
00045 #include <netbuild/NBNode.h>
00046 #include <netbuild/NBNodeCont.h>
00047 #include <netbuild/NBNetBuilder.h>
00048 #include "NILoader.h"
00049 #include "NIImporter_SUMO.h"
00050 
00051 #ifdef CHECK_MEMORY_LEAKS
00052 #include <foreign/nvwa/debug_new.h>
00053 #endif // CHECK_MEMORY_LEAKS
00054 
00055 
00056 // ===========================================================================
00057 // method definitions
00058 // ===========================================================================
00059 // ---------------------------------------------------------------------------
00060 // static methods (interface in this case)
00061 // ---------------------------------------------------------------------------
00062 void
00063 NIImporter_SUMO::loadNetwork(const OptionsCont& oc, NBNetBuilder& nb) {
00064     NIImporter_SUMO importer(nb);
00065     importer._loadNetwork(oc);
00066 }
00067 
00068 
00069 // ---------------------------------------------------------------------------
00070 // loader methods
00071 // ---------------------------------------------------------------------------
00072 NIImporter_SUMO::NIImporter_SUMO(NBNetBuilder& nb)
00073     : SUMOSAXHandler("sumo-network"),
00074       myNetBuilder(nb),
00075       myNodeCont(nb.getNodeCont()),
00076       myTLLCont(nb.getTLLogicCont()),
00077       myCurrentEdge(0),
00078       myCurrentLane(0),
00079       myCurrentTL(0),
00080       myLocation(0),
00081       mySuspectKeepShape(false),
00082       myHaveWarnedAboutDeprecatedSpreadType(false),
00083       myHaveWarnedAboutDeprecatedMaxSpeed(false) {}
00084 
00085 
00086 NIImporter_SUMO::~NIImporter_SUMO() throw() {
00087     for (std::map<std::string, EdgeAttrs*>::const_iterator i=myEdges.begin(); i!=myEdges.end(); ++i) {
00088         EdgeAttrs* ed = (*i).second;
00089         for (std::vector<LaneAttrs*>::const_iterator j=ed->lanes.begin(); j!=ed->lanes.end(); ++j) {
00090             delete *j;
00091         }
00092         delete ed;
00093     }
00094     delete myLocation;
00095 }
00096 
00097 
00098 void
00099 NIImporter_SUMO::_loadNetwork(const OptionsCont& oc) {
00100     // check whether the option is set (properly)
00101     if (!oc.isUsableFileList("sumo-net-file")) {
00102         return;
00103     }
00104     // parse file(s)
00105     std::vector<std::string> files = oc.getStringVector("sumo-net-file");
00106     for (std::vector<std::string>::const_iterator file=files.begin(); file!=files.end(); ++file) {
00107         if (!FileHelpers::exists(*file)) {
00108             WRITE_ERROR("Could not open sumo-net-file '" + *file + "'.");
00109             return;
00110         }
00111         setFileName(*file);
00112         PROGRESS_BEGIN_MESSAGE("Parsing sumo-net from '" + *file + "'");
00113         XMLSubSys::runParser(*this, *file);
00114         PROGRESS_DONE_MESSAGE();
00115     }
00116     // build edges
00117     for (std::map<std::string, EdgeAttrs*>::const_iterator i=myEdges.begin(); i!=myEdges.end(); ++i) {
00118         EdgeAttrs* ed = (*i).second;
00119         // skip internal edges
00120         if (ed->func == toString(EDGEFUNC_INTERNAL)) {
00121             continue;
00122         }
00123         // get and check the nodes
00124         NBNode* from = myNodeCont.retrieve(ed->fromNode);
00125         NBNode* to = myNodeCont.retrieve(ed->toNode);
00126         if (from==0) {
00127             WRITE_ERROR("Edge's '" + ed->id + "' from-node '" + ed->fromNode + "' is not known.");
00128             continue;
00129         }
00130         if (to==0) {
00131             WRITE_ERROR("Edge's '" + ed->id + "' to-node '" + ed->toNode + "' is not known.");
00132             continue;
00133         }
00134         // edge shape
00135         PositionVector geom;
00136         if (ed->shape.size() > 0) {
00137             geom = ed->shape;
00138             mySuspectKeepShape = false; // no problem with reconstruction if edge shape is given explicit
00139         } else {
00140             // either the edge has default shape consisting only of the two node
00141             // positions or we have a legacy network
00142             geom = reconstructEdgeShape(ed, from->getPosition(), to->getPosition());
00143         }
00144         // build and insert the edge
00145         NBEdge* e = new NBEdge(ed->id, from, to,
00146                                ed->type, ed->maxSpeed,
00147                                (unsigned int) ed->lanes.size(),
00148                                ed->priority, NBEdge::UNSPECIFIED_WIDTH, NBEdge::UNSPECIFIED_OFFSET,
00149                                geom, ed->streetName, ed->lsf, true); // always use tryIgnoreNodePositions to keep original shape
00150         if (!myNetBuilder.getEdgeCont().insert(e)) {
00151             WRITE_ERROR("Could not insert edge '" + ed->id + "'.");
00152             delete e;
00153             continue;
00154         }
00155         ed->builtEdge = myNetBuilder.getEdgeCont().retrieve(ed->id);
00156     }
00157     // assign further lane attributes (edges are built)
00158     for (std::map<std::string, EdgeAttrs*>::const_iterator i=myEdges.begin(); i!=myEdges.end(); ++i) {
00159         EdgeAttrs* ed = (*i).second;
00160         NBEdge* nbe = ed->builtEdge;
00161         if (nbe == 0) { // inner edge or removed by explicit list, vclass, ...
00162             continue;
00163         }
00164         for (unsigned int fromLaneIndex=0; fromLaneIndex<(unsigned int) ed->lanes.size(); ++fromLaneIndex) {
00165             LaneAttrs* lane = ed->lanes[fromLaneIndex];
00166             // connections
00167             const std::vector<Connection> &connections = lane->connections;
00168             for (std::vector<Connection>::const_iterator c_it=connections.begin(); c_it!=connections.end(); c_it++) {
00169                 const Connection& c = *c_it;
00170                 if (myEdges.count(c.toEdgeID) == 0) {
00171                     WRITE_ERROR("Unknown edge '" + c.toEdgeID + "' given in connection.");
00172                     continue;
00173                 }
00174                 NBEdge* toEdge = myEdges[c.toEdgeID]->builtEdge;
00175                 if (toEdge==0) { // removed by explicit list, vclass, ...
00176                     continue;
00177                 }
00178                 nbe->addLane2LaneConnection(
00179                     fromLaneIndex, toEdge, c.toLaneIdx, NBEdge::L2L_VALIDATED,
00180                     false, c.mayDefinitelyPass);
00181 
00182                 // maybe we have a tls-controlled connection
00183                 if (c.tlID != "") {
00184                     const std::map<std::string, NBTrafficLightDefinition*>& programs = myTLLCont.getPrograms(c.tlID);
00185                     if (programs.size() > 0) {
00186                         std::map<std::string, NBTrafficLightDefinition*>::const_iterator it;
00187                         for (it = programs.begin(); it!= programs.end(); it++) {
00188                             NBLoadedSUMOTLDef* tlDef = dynamic_cast<NBLoadedSUMOTLDef*>(it->second);
00189                             if (tlDef) {
00190                                 tlDef->addConnection(nbe, toEdge, fromLaneIndex, c.toLaneIdx, c.tlLinkNo);
00191                             } else {
00192                                 throw ProcessError("Corrupt traffic light definition '"
00193                                                    + c.tlID + "' (program '" + it->first + "')");
00194                             }
00195                         }
00196                     } else {
00197                         WRITE_ERROR("The traffic light '" + c.tlID + "' is not known.");
00198                     }
00199                 }
00200             }
00201             // allow/disallow
00202             SUMOVehicleClasses allowed;
00203             SUMOVehicleClasses disallowed;
00204             parseVehicleClasses(lane->allow, lane->disallow, allowed, disallowed);
00205             nbe->setVehicleClasses(allowed, disallowed, fromLaneIndex);
00206             // width, offset
00207             nbe->setWidth(fromLaneIndex, lane->width);
00208             nbe->setOffset(fromLaneIndex, lane->offset);
00209             nbe->setSpeed(fromLaneIndex, lane->maxSpeed);
00210         }
00211         nbe->declareConnectionsAsLoaded();
00212     }
00213     // insert loaded prohibitions
00214     for (std::vector<Prohibition>::const_iterator it = myProhibitions.begin(); it != myProhibitions.end(); it++) {
00215         NBEdge* prohibitedFrom = myEdges[it->prohibitedFrom]->builtEdge;
00216         if (prohibitedFrom == 0) {
00217             WRITE_ERROR("Edge '" + it->prohibitedFrom + "' in prohibition was not built");
00218         } else {
00219             NBNode* n = prohibitedFrom->getToNode();
00220             n->addSortedLinkFoes(
00221                 NBConnection(myEdges[it->prohibitorFrom]->builtEdge, myEdges[it->prohibitorTo]->builtEdge),
00222                 NBConnection(prohibitedFrom, myEdges[it->prohibitedTo]->builtEdge));
00223         }
00224     }
00225 
00226     // final warning
00227     if (mySuspectKeepShape) {
00228         WRITE_WARNING("The input network may have been built using option 'xml.keep-shape'.\n... Accuracy of junction positions cannot be guaranteed.");
00229     }
00230 
00231 }
00232 
00233 
00234 
00235 void
00236 NIImporter_SUMO::myStartElement(int element,
00237                                 const SUMOSAXAttributes& attrs) throw(ProcessError) {
00238     /* our goal is to reproduce the input net faithfully
00239      * there are different types of objects in the netfile:
00240      * 1) those which must be loaded into NBNetBuilder-Containers for processing
00241      * 2) those which can be ignored because they are recomputed based on group 1
00242      * 3) those which are of no concern to NBNetBuilder but should be exposed to
00243      *      NETEDIT. We will probably have to patch NBNetBuilder to contain them
00244      *      and hand them over to NETEDIT
00245      *    alternative idea: those shouldn't really be contained within the
00246      *    network but rather in separate files. teach NETEDIT how to open those
00247      *    (POI?)
00248      * 4) those which are of concern neither to NBNetBuilder nor NETEDIT and
00249      *    must be copied over - need to patch NBNetBuilder for this.
00250      *    copy unknown by default
00251      */
00252     switch (element) {
00253     case SUMO_TAG_EDGE:
00254         addEdge(attrs);
00255         break;
00256     case SUMO_TAG_LANE:
00257         addLane(attrs);
00258         break;
00259     case SUMO_TAG_JUNCTION:
00260         addJunction(attrs);
00261         break;
00262     case SUMO_TAG_SUCC:
00263         addSuccEdge(attrs);
00264         break;
00265     case SUMO_TAG_SUCCLANE:
00266         addSuccLane(attrs);
00267         break;
00268     case SUMO_TAG_CONNECTION:
00269         addConnection(attrs);
00270         break;
00271     case SUMO_TAG_TLLOGIC__DEPRECATED:
00272     case SUMO_TAG_TLLOGIC:
00273         myCurrentTL = initTrafficLightLogic(attrs, myCurrentTL);
00274         break;
00275     case SUMO_TAG_PHASE:
00276         addPhase(attrs, myCurrentTL);
00277         break;
00278     case SUMO_TAG_LOCATION:
00279         setLocation(attrs);
00280         break;
00281     case SUMO_TAG_PROHIBITION:
00282         addProhibition(attrs);
00283         break;
00284     default:
00285         break;
00286     }
00287 }
00288 
00289 
00290 void
00291 NIImporter_SUMO::myCharacters(int element,
00292                               const std::string& chars) throw(ProcessError) {
00293     UNUSED_PARAMETER(element);
00294     UNUSED_PARAMETER(chars);
00295 }
00296 
00297 
00298 void
00299 NIImporter_SUMO::myEndElement(int element) throw(ProcessError) {
00300     switch (element) {
00301     case SUMO_TAG_EDGE:
00302         if (myEdges.find(myCurrentEdge->id)!=myEdges.end()) {
00303             WRITE_ERROR("Edge '" + myCurrentEdge->id + "' occured at least twice in the input.");
00304         } else {
00305             myEdges[myCurrentEdge->id] = myCurrentEdge;
00306         }
00307         myCurrentEdge = 0;
00308         break;
00309     case SUMO_TAG_LANE:
00310         if (myCurrentEdge!=0) {
00311             myCurrentEdge->maxSpeed = MAX2(myCurrentEdge->maxSpeed, myCurrentLane->maxSpeed);
00312             myCurrentEdge->lanes.push_back(myCurrentLane);
00313         }
00314         myCurrentLane = 0;
00315         break;
00316     case SUMO_TAG_TLLOGIC__DEPRECATED:
00317     case SUMO_TAG_TLLOGIC:
00318         if (!myCurrentTL) {
00319             WRITE_ERROR("Unmatched closing tag for tl-logic.");
00320         } else {
00321             if (!myTLLCont.insert(myCurrentTL)) {
00322                 WRITE_WARNING("Could not add program '" + myCurrentTL->getProgramID() +
00323                               "' for traffic light '" + myCurrentTL->getID() + "'");
00324                 delete myCurrentTL;
00325             }
00326             myCurrentTL = 0;
00327         }
00328         break;
00329     default:
00330         break;
00331     }
00332 }
00333 
00334 
00335 void
00336 NIImporter_SUMO::addEdge(const SUMOSAXAttributes& attrs) {
00337     // get the id, report an error if not given or empty...
00338     bool ok = true;
00339     std::string id = attrs.getStringReporting(SUMO_ATTR_ID, 0, ok);
00340     if (!ok) {
00341         return;
00342     }
00343     myCurrentEdge = new EdgeAttrs;
00344     myCurrentEdge->builtEdge = 0;
00345     myCurrentEdge->id = id;
00346     // get the function
00347     myCurrentEdge->func = attrs.getOptStringReporting(SUMO_ATTR_FUNCTION, id.c_str(), ok, "normal");
00348     if (myCurrentEdge->func == toString(EDGEFUNC_INTERNAL)) {
00349         return; // skip internal edges
00350     }
00351     // get the type
00352     myCurrentEdge->type = attrs.getOptStringReporting(SUMO_ATTR_TYPE, id.c_str(), ok, "");
00353     // get the origin and the destination node
00354     myCurrentEdge->fromNode = attrs.getOptStringReporting(SUMO_ATTR_FROM, id.c_str(), ok, "");
00355     myCurrentEdge->toNode = attrs.getOptStringReporting(SUMO_ATTR_TO, id.c_str(), ok, "");
00356     myCurrentEdge->priority = attrs.getOptIntReporting(SUMO_ATTR_PRIORITY, id.c_str(), ok, -1);
00357     myCurrentEdge->type = attrs.getOptStringReporting(SUMO_ATTR_TYPE, id.c_str(), ok, "");
00358     myCurrentEdge->shape = GeomConvHelper::parseShapeReporting(
00359                                attrs.getOptStringReporting(SUMO_ATTR_SHAPE, id.c_str(), ok, ""),
00360                                attrs.getObjectType(), id.c_str(), ok, true);
00361     NILoader::transformCoordinates(myCurrentEdge->shape, true, myLocation);
00362     myCurrentEdge->maxSpeed = 0;
00363     myCurrentEdge->streetName = attrs.getOptStringReporting(SUMO_ATTR_NAME, id.c_str(), ok, "");
00364 
00365     std::string lsfS = toString(LANESPREAD_RIGHT);
00366     if (attrs.hasAttribute(SUMO_ATTR_SPREADFUNC__DEPRECATED)) {
00367         lsfS = attrs.getStringReporting(SUMO_ATTR_SPREADFUNC__DEPRECATED, id.c_str(), ok);
00368         if (!myHaveWarnedAboutDeprecatedSpreadType) {
00369             WRITE_WARNING("'" + toString(SUMO_ATTR_SPREADFUNC__DEPRECATED) + "' is deprecated; please use '" + toString(SUMO_ATTR_SPREADTYPE) + "'.");
00370             myHaveWarnedAboutDeprecatedSpreadType = true;
00371         }
00372     } else {
00373         lsfS = attrs.getOptStringReporting(SUMO_ATTR_SPREADTYPE, id.c_str(), ok, lsfS);
00374     }
00375     if (SUMOXMLDefinitions::LaneSpreadFunctions.hasString(lsfS)) {
00376         myCurrentEdge->lsf = SUMOXMLDefinitions::LaneSpreadFunctions.get(lsfS);
00377     } else {
00378         WRITE_ERROR("Unknown spreadType '" + lsfS + "' for edge '" + id + "'.");
00379     }
00380 }
00381 
00382 
00383 void
00384 NIImporter_SUMO::addLane(const SUMOSAXAttributes& attrs) {
00385     bool ok = true;
00386     std::string id = attrs.getStringReporting(SUMO_ATTR_ID, 0, ok);
00387     if (!ok) {
00388         return;
00389     }
00390     if (!myCurrentEdge) {
00391         WRITE_ERROR("Found lane '" + id  + "' not within edge element");
00392         return;
00393     }
00394     myCurrentLane = new LaneAttrs;
00395     if (myCurrentEdge->func == toString(EDGEFUNC_INTERNAL)) {
00396         return; // skip internal lanes
00397     }
00398     if (attrs.hasAttribute(SUMO_ATTR_MAXSPEED__DEPRECATED)) {
00399         myCurrentLane->maxSpeed = attrs.getSUMORealReporting(SUMO_ATTR_MAXSPEED__DEPRECATED, id.c_str(), ok);
00400         if (!myHaveWarnedAboutDeprecatedMaxSpeed) {
00401             myHaveWarnedAboutDeprecatedMaxSpeed = true;
00402             WRITE_WARNING("'" + toString(SUMO_ATTR_MAXSPEED__DEPRECATED) + "' is deprecated, please use '" + toString(SUMO_ATTR_SPEED) + "' instead.");
00403         }
00404     } else {
00405         myCurrentLane->maxSpeed = attrs.getSUMORealReporting(SUMO_ATTR_SPEED, id.c_str(), ok);
00406     }
00407     myCurrentLane->allow = attrs.getOptStringReporting(SUMO_ATTR_ALLOW, id.c_str(), ok, "");
00408     myCurrentLane->disallow = attrs.getOptStringReporting(SUMO_ATTR_DISALLOW, id.c_str(), ok, "");
00409     myCurrentLane->width = attrs.getOptSUMORealReporting(SUMO_ATTR_WIDTH, id.c_str(), ok, (SUMOReal) NBEdge::UNSPECIFIED_WIDTH);
00410     myCurrentLane->offset = attrs.getOptSUMORealReporting(SUMO_ATTR_ENDOFFSET, id.c_str(), ok, (SUMOReal) NBEdge::UNSPECIFIED_OFFSET);
00411     myCurrentLane->shape = GeomConvHelper::parseShapeReporting(
00412                                attrs.getStringReporting(SUMO_ATTR_SHAPE, id.c_str(), ok),
00413                                attrs.getObjectType(), id.c_str(), ok, false);
00414     // lane coordinates are derived (via lane spread) do not include them in convex boundary
00415     NILoader::transformCoordinates(myCurrentLane->shape, false, myLocation);
00416 }
00417 
00418 
00419 void
00420 NIImporter_SUMO::addJunction(const SUMOSAXAttributes& attrs) {
00421     // get the id, report an error if not given or empty...
00422     bool ok = true;
00423     std::string id = attrs.getStringReporting(SUMO_ATTR_ID, 0, ok);
00424     if (!ok) {
00425         return;
00426     }
00427     if (id[0]==':') { // internal node
00428         return;
00429     }
00430     SumoXMLNodeType type = NODETYPE_UNKNOWN;
00431     std::string typeS = attrs.getStringReporting(SUMO_ATTR_TYPE, id.c_str(), ok);
00432     if (SUMOXMLDefinitions::NodeTypes.hasString(typeS)) {
00433         type = SUMOXMLDefinitions::NodeTypes.get(typeS);
00434         if (type == NODETYPE_DEAD_END_DEPRECATED) { // patch legacy type
00435             type = NODETYPE_DEAD_END;
00436         }
00437     } else {
00438         WRITE_WARNING("Unknown node type '" + typeS + "' for junction '" + id + "'.");
00439     }
00440     Position pos = readPosition(attrs, id, ok);
00441     NILoader::transformCoordinates(pos, true, myLocation);
00442     // the network may have been built with the option "plain.keep-edge-shape" this
00443     // makes accurate reconstruction of legacy networks impossible. We ought to warn about this
00444     std::string shapeS = attrs.getStringReporting(SUMO_ATTR_SHAPE, id.c_str(), ok, false);
00445     if (shapeS != "") {
00446         PositionVector shape = GeomConvHelper::parseShapeReporting(
00447                                    shapeS, attrs.getObjectType(), id.c_str(), ok, false);
00448         shape.push_back(shape[0]); // need closed shape
00449         if (!shape.around(pos) && shape.distance(pos) > 1) { // MAGIC_THRESHOLD
00450             // WRITE_WARNING("Junction '" + id + "': distance between pos and shape is " + toString(shape.distance(pos)));
00451             mySuspectKeepShape = true;
00452         }
00453     }
00454     NBNode* node = new NBNode(id, pos, type);
00455     if (!myNodeCont.insert(node)) {
00456         WRITE_ERROR("Problems on adding junction '" + id + "'.");
00457         delete node;
00458         return;
00459     }
00460 }
00461 
00462 
00463 void
00464 NIImporter_SUMO::addSuccEdge(const SUMOSAXAttributes& attrs) {
00465     bool ok = true;
00466     std::string edge_id = attrs.getStringReporting(SUMO_ATTR_EDGE, 0, ok);
00467     myCurrentEdge = 0;
00468     if (myEdges.count(edge_id) == 0) {
00469         WRITE_ERROR("Unknown edge '" + edge_id + "' given in succedge.");
00470         return;
00471     }
00472     myCurrentEdge = myEdges[edge_id];
00473     std::string lane_id = attrs.getStringReporting(SUMO_ATTR_LANE, 0, ok);
00474     myCurrentLane = getLaneAttrsFromID(myCurrentEdge, lane_id);
00475 }
00476 
00477 
00478 void
00479 NIImporter_SUMO::addSuccLane(const SUMOSAXAttributes& attrs) {
00480     if (myCurrentLane==0) {
00481         WRITE_ERROR("Found succlane outside succ element");
00482         return;
00483     }
00484     bool ok = true;
00485     Connection conn;
00486     std::string laneID = attrs.getStringReporting(SUMO_ATTR_LANE, 0, ok);
00487     if (laneID == "SUMO_NO_DESTINATION") { // legacy check
00488         // deprecated
00489         return;
00490     }
00491     interpretLaneID(laneID, conn.toEdgeID, conn.toLaneIdx);
00492     conn.tlID = attrs.getOptStringReporting(SUMO_ATTR_TLID, 0, ok, "");
00493     conn.mayDefinitelyPass = false; // (attrs.getStringReporting(SUMO_ATTR_STATE, 0, ok, "") == "M");
00494     if (conn.tlID != "") {
00495         conn.tlLinkNo = attrs.hasAttribute(SUMO_ATTR_TLLINKINDEX)
00496                         ? attrs.getIntReporting(SUMO_ATTR_TLLINKINDEX, 0, ok)
00497                         : attrs.getIntReporting(SUMO_ATTR_TLLINKNO__DEPRECATED, 0, ok);
00498     }
00499     myCurrentLane->connections.push_back(conn);
00500 }
00501 
00502 
00503 void
00504 NIImporter_SUMO::addConnection(const SUMOSAXAttributes& attrs) {
00505     bool ok = true;
00506     std::string fromID = attrs.getStringReporting(SUMO_ATTR_FROM, 0, ok);
00507     if (myEdges.count(fromID) == 0) {
00508         WRITE_ERROR("Unknown edge '" + fromID + "' given in connection.");
00509         return;
00510     }
00511     EdgeAttrs* from = myEdges[fromID];
00512     Connection conn;
00513     conn.toEdgeID = attrs.getStringReporting(SUMO_ATTR_TO, 0, ok);
00514     unsigned int fromLaneIdx = attrs.getIntReporting(SUMO_ATTR_FROM_LANE, 0, ok);
00515     conn.toLaneIdx = attrs.getIntReporting(SUMO_ATTR_TO_LANE, 0, ok);
00516     conn.tlID = attrs.getOptStringReporting(SUMO_ATTR_TLID, 0, ok, "");
00517     conn.mayDefinitelyPass = false; // (attrs.getStringReporting(SUMO_ATTR_STATE, 0, ok, "") == "M");
00518     if (conn.tlID != "") {
00519         conn.tlLinkNo = attrs.getIntReporting(SUMO_ATTR_TLLINKINDEX, 0, ok);
00520     }
00521 
00522     if (from->lanes.size()<=(size_t) fromLaneIdx) {
00523         WRITE_ERROR("Invalid lane index '" + toString(fromLaneIdx) + "' for connection from '" + fromID + "'.");
00524         return;
00525     }
00526     from->lanes[fromLaneIdx]->connections.push_back(conn);
00527 }
00528 
00529 
00530 void
00531 NIImporter_SUMO::addProhibition(const SUMOSAXAttributes& attrs) {
00532     bool ok = true;
00533     std::string prohibitor = attrs.getOptStringReporting(SUMO_ATTR_PROHIBITOR, 0, ok, "");
00534     std::string prohibited = attrs.getOptStringReporting(SUMO_ATTR_PROHIBITED, 0, ok, "");
00535     if (!ok) {
00536         return;
00537     }
00538     Prohibition p;
00539     parseProhibitionConnection(prohibitor, p.prohibitorFrom, p.prohibitorTo, ok);
00540     parseProhibitionConnection(prohibited, p.prohibitedFrom, p.prohibitedTo, ok);
00541     if (!ok) {
00542         return;
00543     }
00544     myProhibitions.push_back(p);
00545 }
00546 
00547 
00548 NIImporter_SUMO::LaneAttrs*
00549 NIImporter_SUMO::getLaneAttrsFromID(EdgeAttrs* edge, std::string lane_id) {
00550     std::string edge_id;
00551     unsigned int index;
00552     interpretLaneID(lane_id, edge_id, index);
00553     assert(edge->id == edge_id);
00554     if (edge->lanes.size()<=(size_t) index) {
00555         WRITE_ERROR("Unknown lane '" + lane_id + "' given in succedge.");
00556         return 0;
00557     } else {
00558         return edge->lanes[index];
00559     }
00560 }
00561 
00562 
00563 void
00564 NIImporter_SUMO::interpretLaneID(const std::string& lane_id, std::string& edge_id, unsigned int& index) {
00565     // assume lane_id = edge_id + '_' + index
00566     size_t sep_index = lane_id.rfind('_');
00567     if (sep_index == std::string::npos) {
00568         WRITE_ERROR("Invalid lane id '" + lane_id + "' (missing '_').");
00569     }
00570     edge_id = lane_id.substr(0, sep_index);
00571     std::string index_string = lane_id.substr(sep_index + 1);
00572     try {
00573         index = (unsigned int)TplConvert<char>::_2int(index_string.c_str());
00574     } catch (NumberFormatException) {
00575         WRITE_ERROR("Invalid lane index '" + index_string + "' for lane '" + lane_id + "'.");
00576     }
00577 }
00578 
00579 
00580 NBLoadedSUMOTLDef*
00581 NIImporter_SUMO::initTrafficLightLogic(const SUMOSAXAttributes& attrs, NBLoadedSUMOTLDef* currentTL) {
00582     if (currentTL) {
00583         WRITE_ERROR("Definition of tl-logic '" + currentTL->getID() + "' was not finished.");
00584         return 0;
00585     }
00586     bool ok = true;
00587     std::string id = attrs.getStringReporting(SUMO_ATTR_ID, 0, ok);
00588     SUMOTime offset = TIME2STEPS(attrs.getSUMORealReporting(SUMO_ATTR_OFFSET, id.c_str(), ok));
00589     std::string programID = attrs.getOptStringReporting(SUMO_ATTR_PROGRAMID, id.c_str(), ok, "<unknown>");
00590     std::string type = attrs.getStringReporting(SUMO_ATTR_TYPE, 0, ok);
00591     if (type != toString(TLTYPE_STATIC)) {
00592         WRITE_WARNING("Traffic light '" + id + "' has unsupported type '" + type + "' and will be converted to '" +
00593                       toString(TLTYPE_STATIC) + "'");
00594     }
00595     if (ok) {
00596         return new NBLoadedSUMOTLDef(id, programID, offset);
00597     } else {
00598         return 0;
00599     }
00600 }
00601 
00602 
00603 void
00604 NIImporter_SUMO::addPhase(const SUMOSAXAttributes& attrs, NBLoadedSUMOTLDef* currentTL) {
00605     if (!currentTL) {
00606         WRITE_ERROR("found phase without tl-logic");
00607         return;
00608     }
00609     const std::string& id = currentTL->getID();
00610     bool ok = true;
00611     std::string state = attrs.getStringReporting(SUMO_ATTR_STATE, id.c_str(), ok);
00612     SUMOTime duration = TIME2STEPS(attrs.getSUMORealReporting(SUMO_ATTR_DURATION, id.c_str(), ok));
00613     if (duration < 0) {
00614         WRITE_ERROR("Phase duration for tl-logic '" + id + "/" + currentTL->getProgramID() + "' must be positive.");
00615         return;
00616     }
00617     // if the traffic light is an actuated traffic light, try to get
00618     //  the minimum and maximum durations
00619     //SUMOTime minDuration = attrs.getOptSUMOTimeReporting(SUMO_ATTR_MINDURATION, id.c_str(), ok, -1);
00620     //SUMOTime maxDuration = attrs.getOptSUMOTimeReporting(SUMO_ATTR_MAXDURATION, id.c_str(), ok, -1);
00621     if (ok) {
00622         currentTL->addPhase(duration, state);
00623     }
00624 }
00625 
00626 
00627 PositionVector
00628 NIImporter_SUMO::reconstructEdgeShape(const EdgeAttrs* edge, const Position& from, const Position& to) {
00629     const PositionVector& firstLane = edge->lanes[0]->shape;
00630     PositionVector result;
00631     result.push_back(from);
00632 
00633     // reverse logic of NBEdge::computeLaneShape
00634     // !!! this will only work for old-style constant width lanes
00635     const size_t noLanes = edge->lanes.size();
00636     for (unsigned int i=1; i < firstLane.size() - 1; i++) {
00637         Position from = firstLane[i-1];
00638         Position me = firstLane[i];
00639         Position to = firstLane[i+1];
00640         std::pair<SUMOReal, SUMOReal> offsets = NBEdge::laneOffset(
00641                 from, me, SUMO_const_laneWidthAndOffset, (unsigned int)noLanes-1,
00642                 noLanes, edge->lsf, false);
00643         std::pair<SUMOReal, SUMOReal> offsets2 = NBEdge::laneOffset(
00644                     me, to, SUMO_const_laneWidthAndOffset, (unsigned int)noLanes-1,
00645                     noLanes, edge->lsf, false);
00646 
00647         Line l1(
00648             Position(from.x()+offsets.first, from.y()+offsets.second),
00649             Position(me.x()+offsets.first, me.y()+offsets.second));
00650         l1.extrapolateBy(100);
00651         Line l2(
00652             Position(me.x()+offsets2.first, me.y()+offsets2.second),
00653             Position(to.x()+offsets2.first, to.y()+offsets2.second));
00654         l2.extrapolateBy(100);
00655         if (l1.intersects(l2)) {
00656             result.push_back(l1.intersectsAt(l2));
00657         } else {
00658             WRITE_WARNING("Could not reconstruct shape for edge '" + edge->id + "'.");
00659         }
00660     }
00661 
00662     result.push_back(to);
00663     return result;
00664 }
00665 
00666 
00667 void
00668 NIImporter_SUMO::setLocation(const SUMOSAXAttributes& attrs) {
00669     // @todo refactor parsing of location since its duplicated in NLHandler and PCNetProjectionLoader
00670     bool ok = true;
00671     PositionVector s = GeomConvHelper::parseShapeReporting(
00672                            attrs.getStringReporting(SUMO_ATTR_NET_OFFSET, 0, ok),
00673                            attrs.getObjectType(), 0, ok, false);
00674     Boundary convBoundary = GeomConvHelper::parseBoundaryReporting(
00675                                 attrs.getStringReporting(SUMO_ATTR_CONV_BOUNDARY, 0, ok),
00676                                 attrs.getObjectType(), 0, ok);
00677     Boundary origBoundary = GeomConvHelper::parseBoundaryReporting(
00678                                 attrs.getStringReporting(SUMO_ATTR_ORIG_BOUNDARY, 0, ok),
00679                                 attrs.getObjectType(), 0, ok);
00680     std::string proj = attrs.getStringReporting(SUMO_ATTR_ORIG_PROJ, 0, ok);
00681     if (ok) {
00682         Position networkOffset = s[0];
00683         myLocation = new GeoConvHelper(proj, networkOffset, origBoundary, convBoundary);
00684         GeoConvHelper::setLoaded(*myLocation);
00685     }
00686 }
00687 
00688 
00689 Position
00690 NIImporter_SUMO::readPosition(const SUMOSAXAttributes& attrs, const std::string& id, bool& ok) {
00691     SUMOReal x = attrs.getSUMORealReporting(SUMO_ATTR_X, id.c_str(), ok);
00692     SUMOReal y = attrs.getSUMORealReporting(SUMO_ATTR_Y, id.c_str(), ok);
00693     SUMOReal z = 0;
00694     if (attrs.hasAttribute(SUMO_ATTR_Z)) {
00695         z = attrs.getSUMORealReporting(SUMO_ATTR_Z, id.c_str(), ok);
00696     }
00697     return Position(x,y,z);
00698 }
00699 
00700 
00701 void
00702 NIImporter_SUMO::parseProhibitionConnection(const std::string& attr, std::string& from, std::string& to, bool& ok) {
00703     // split from/to
00704     size_t div = attr.find("->");
00705     if (div==std::string::npos) {
00706         WRITE_ERROR("Missing connection divider in prohibition attribute '" + attr + "'");
00707         ok = false;
00708     }
00709     from = attr.substr(0, div);
00710     to = attr.substr(div+2);
00711     // check whether the definition includes a lane information and discard it
00712     if (from.find('_')!=std::string::npos) {
00713         from= from.substr(0, from.find('_'));
00714     }
00715     if (to.find('_')!=std::string::npos) {
00716         to= to.substr(0, to.find('_'));
00717     }
00718     // check whether the edges are known
00719     if (myEdges.count(from) == 0) {
00720         WRITE_ERROR("Unknown edge prohibition '" + from + "'");
00721         ok = false;
00722     }
00723     if (myEdges.count(to) == 0) {
00724         WRITE_ERROR("Unknown edge prohibition '" + to + "'");
00725         ok = false;
00726     }
00727 }
00728 /****************************************************************************/
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Defines