SUMO - Simulation of Urban MObility

NIImporter_SUMO.cpp

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