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 XXX preferred
00206             nbe->setPermissions(parseVehicleClasses(lane->allow, lane->disallow), fromLaneIndex);
00207             // width, offset
00208             nbe->setWidth(fromLaneIndex, lane->width);
00209             nbe->setOffset(fromLaneIndex, lane->offset);
00210             nbe->setSpeed(fromLaneIndex, lane->maxSpeed);
00211         }
00212         nbe->declareConnectionsAsLoaded();
00213     }
00214     // insert loaded prohibitions
00215     for (std::vector<Prohibition>::const_iterator it = myProhibitions.begin(); it != myProhibitions.end(); it++) {
00216         NBEdge* prohibitedFrom = myEdges[it->prohibitedFrom]->builtEdge;
00217         if (prohibitedFrom == 0) {
00218             WRITE_ERROR("Edge '" + it->prohibitedFrom + "' in prohibition was not built");
00219         } else {
00220             NBNode* n = prohibitedFrom->getToNode();
00221             n->addSortedLinkFoes(
00222                 NBConnection(myEdges[it->prohibitorFrom]->builtEdge, myEdges[it->prohibitorTo]->builtEdge),
00223                 NBConnection(prohibitedFrom, myEdges[it->prohibitedTo]->builtEdge));
00224         }
00225     }
00226 
00227     // final warning
00228     if (mySuspectKeepShape) {
00229         WRITE_WARNING("The input network may have been built using option 'xml.keep-shape'.\n... Accuracy of junction positions cannot be guaranteed.");
00230     }
00231 
00232 }
00233 
00234 
00235 
00236 void
00237 NIImporter_SUMO::myStartElement(int element,
00238                                 const SUMOSAXAttributes& attrs) {
00239     /* our goal is to reproduce the input net faithfully
00240      * there are different types of objects in the netfile:
00241      * 1) those which must be loaded into NBNetBuilder-Containers for processing
00242      * 2) those which can be ignored because they are recomputed based on group 1
00243      * 3) those which are of no concern to NBNetBuilder but should be exposed to
00244      *      NETEDIT. We will probably have to patch NBNetBuilder to contain them
00245      *      and hand them over to NETEDIT
00246      *    alternative idea: those shouldn't really be contained within the
00247      *    network but rather in separate files. teach NETEDIT how to open those
00248      *    (POI?)
00249      * 4) those which are of concern neither to NBNetBuilder nor NETEDIT and
00250      *    must be copied over - need to patch NBNetBuilder for this.
00251      *    copy unknown by default
00252      */
00253     switch (element) {
00254         case SUMO_TAG_EDGE:
00255             addEdge(attrs);
00256             break;
00257         case SUMO_TAG_LANE:
00258             addLane(attrs);
00259             break;
00260         case SUMO_TAG_JUNCTION:
00261             addJunction(attrs);
00262             break;
00263         case SUMO_TAG_SUCC:
00264             addSuccEdge(attrs);
00265             break;
00266         case SUMO_TAG_SUCCLANE:
00267             addSuccLane(attrs);
00268             break;
00269         case SUMO_TAG_CONNECTION:
00270             addConnection(attrs);
00271             break;
00272         case SUMO_TAG_TLLOGIC__DEPRECATED:
00273         case SUMO_TAG_TLLOGIC:
00274             myCurrentTL = initTrafficLightLogic(attrs, myCurrentTL);
00275             break;
00276         case SUMO_TAG_PHASE:
00277             addPhase(attrs, myCurrentTL);
00278             break;
00279         case SUMO_TAG_LOCATION:
00280             myLocation = loadLocation(attrs);
00281             break;
00282         case SUMO_TAG_PROHIBITION:
00283             addProhibition(attrs);
00284             break;
00285         default:
00286             break;
00287     }
00288 }
00289 
00290 
00291 void
00292 NIImporter_SUMO::myCharacters(int element,
00293                               const std::string& chars) {
00294     UNUSED_PARAMETER(element);
00295     UNUSED_PARAMETER(chars);
00296 }
00297 
00298 
00299 void
00300 NIImporter_SUMO::myEndElement(int element) {
00301     switch (element) {
00302         case SUMO_TAG_EDGE:
00303             if (myEdges.find(myCurrentEdge->id) != myEdges.end()) {
00304                 WRITE_ERROR("Edge '" + myCurrentEdge->id + "' occured at least twice in the input.");
00305             } else {
00306                 myEdges[myCurrentEdge->id] = myCurrentEdge;
00307             }
00308             myCurrentEdge = 0;
00309             break;
00310         case SUMO_TAG_LANE:
00311             if (myCurrentEdge != 0) {
00312                 myCurrentEdge->maxSpeed = MAX2(myCurrentEdge->maxSpeed, myCurrentLane->maxSpeed);
00313                 myCurrentEdge->lanes.push_back(myCurrentLane);
00314             }
00315             myCurrentLane = 0;
00316             break;
00317         case SUMO_TAG_TLLOGIC__DEPRECATED:
00318         case SUMO_TAG_TLLOGIC:
00319             if (!myCurrentTL) {
00320                 WRITE_ERROR("Unmatched closing tag for tl-logic.");
00321             } else {
00322                 if (!myTLLCont.insert(myCurrentTL)) {
00323                     WRITE_WARNING("Could not add program '" + myCurrentTL->getProgramID() +
00324                                   "' for traffic light '" + myCurrentTL->getID() + "'");
00325                     delete myCurrentTL;
00326                 }
00327                 myCurrentTL = 0;
00328             }
00329             break;
00330         default:
00331             break;
00332     }
00333 }
00334 
00335 
00336 void
00337 NIImporter_SUMO::addEdge(const SUMOSAXAttributes& attrs) {
00338     // get the id, report an error if not given or empty...
00339     bool ok = true;
00340     std::string id = attrs.getStringReporting(SUMO_ATTR_ID, 0, ok);
00341     if (!ok) {
00342         return;
00343     }
00344     myCurrentEdge = new EdgeAttrs();
00345     myCurrentEdge->builtEdge = 0;
00346     myCurrentEdge->id = id;
00347     // get the function
00348     myCurrentEdge->func = attrs.getOptStringReporting(SUMO_ATTR_FUNCTION, id.c_str(), ok, "normal");
00349     if (myCurrentEdge->func == toString(EDGEFUNC_INTERNAL)) {
00350         return; // skip internal edges
00351     }
00352     // get the type
00353     myCurrentEdge->type = attrs.getOptStringReporting(SUMO_ATTR_TYPE, id.c_str(), ok, "");
00354     // get the origin and the destination node
00355     myCurrentEdge->fromNode = attrs.getOptStringReporting(SUMO_ATTR_FROM, id.c_str(), ok, "");
00356     myCurrentEdge->toNode = attrs.getOptStringReporting(SUMO_ATTR_TO, id.c_str(), ok, "");
00357     myCurrentEdge->priority = attrs.getOptIntReporting(SUMO_ATTR_PRIORITY, id.c_str(), ok, -1);
00358     myCurrentEdge->type = attrs.getOptStringReporting(SUMO_ATTR_TYPE, id.c_str(), ok, "");
00359     myCurrentEdge->shape = GeomConvHelper::parseShapeReporting(
00360                                attrs.getOptStringReporting(SUMO_ATTR_SHAPE, id.c_str(), ok, ""),
00361                                attrs.getObjectType(), id.c_str(), ok, true);
00362     NILoader::transformCoordinates(myCurrentEdge->shape, true, myLocation);
00363     myCurrentEdge->length = attrs.getOptSUMORealReporting(SUMO_ATTR_LENGTH, id.c_str(), ok, NBEdge::UNSPECIFIED_LOADED_LENGTH);
00364     myCurrentEdge->maxSpeed = 0;
00365     myCurrentEdge->streetName = attrs.getOptStringReporting(SUMO_ATTR_NAME, id.c_str(), ok, "");
00366 
00367     std::string lsfS = toString(LANESPREAD_RIGHT);
00368     if (attrs.hasAttribute(SUMO_ATTR_SPREADFUNC__DEPRECATED)) {
00369         lsfS = attrs.getStringReporting(SUMO_ATTR_SPREADFUNC__DEPRECATED, id.c_str(), ok);
00370         if (!myHaveWarnedAboutDeprecatedSpreadType) {
00371             WRITE_WARNING("'" + toString(SUMO_ATTR_SPREADFUNC__DEPRECATED) + "' is deprecated; please use '" + toString(SUMO_ATTR_SPREADTYPE) + "'.");
00372             myHaveWarnedAboutDeprecatedSpreadType = true;
00373         }
00374     } else {
00375         lsfS = attrs.getOptStringReporting(SUMO_ATTR_SPREADTYPE, id.c_str(), ok, lsfS);
00376     }
00377     if (SUMOXMLDefinitions::LaneSpreadFunctions.hasString(lsfS)) {
00378         myCurrentEdge->lsf = SUMOXMLDefinitions::LaneSpreadFunctions.get(lsfS);
00379     } else {
00380         WRITE_ERROR("Unknown spreadType '" + lsfS + "' for edge '" + id + "'.");
00381     }
00382 }
00383 
00384 
00385 void
00386 NIImporter_SUMO::addLane(const SUMOSAXAttributes& attrs) {
00387     bool ok = true;
00388     std::string id = attrs.getStringReporting(SUMO_ATTR_ID, 0, ok);
00389     if (!ok) {
00390         return;
00391     }
00392     if (!myCurrentEdge) {
00393         WRITE_ERROR("Found lane '" + id  + "' not within edge element");
00394         return;
00395     }
00396     myCurrentLane = new LaneAttrs;
00397     if (myCurrentEdge->func == toString(EDGEFUNC_INTERNAL)) {
00398         return; // skip internal lanes
00399     }
00400     if (attrs.hasAttribute(SUMO_ATTR_MAXSPEED__DEPRECATED)) {
00401         myCurrentLane->maxSpeed = attrs.getSUMORealReporting(SUMO_ATTR_MAXSPEED__DEPRECATED, id.c_str(), ok);
00402         if (!myHaveWarnedAboutDeprecatedMaxSpeed) {
00403             myHaveWarnedAboutDeprecatedMaxSpeed = true;
00404             WRITE_WARNING("'" + toString(SUMO_ATTR_MAXSPEED__DEPRECATED) + "' is deprecated, please use '" + toString(SUMO_ATTR_SPEED) + "' instead.");
00405         }
00406     } else {
00407         myCurrentLane->maxSpeed = attrs.getSUMORealReporting(SUMO_ATTR_SPEED, id.c_str(), ok);
00408     }
00409     myCurrentLane->allow = attrs.getOptStringReporting(SUMO_ATTR_ALLOW, id.c_str(), ok, "");
00410     myCurrentLane->disallow = attrs.getOptStringReporting(SUMO_ATTR_DISALLOW, id.c_str(), ok, "");
00411     myCurrentLane->width = attrs.getOptSUMORealReporting(SUMO_ATTR_WIDTH, id.c_str(), ok, (SUMOReal) NBEdge::UNSPECIFIED_WIDTH);
00412     myCurrentLane->offset = attrs.getOptSUMORealReporting(SUMO_ATTR_ENDOFFSET, id.c_str(), ok, (SUMOReal) NBEdge::UNSPECIFIED_OFFSET);
00413     myCurrentLane->shape = GeomConvHelper::parseShapeReporting(
00414                                attrs.getStringReporting(SUMO_ATTR_SHAPE, id.c_str(), ok),
00415                                attrs.getObjectType(), id.c_str(), ok, false);
00416     // lane coordinates are derived (via lane spread) do not include them in convex boundary
00417     NILoader::transformCoordinates(myCurrentLane->shape, false, myLocation);
00418 }
00419 
00420 
00421 void
00422 NIImporter_SUMO::addJunction(const SUMOSAXAttributes& attrs) {
00423     // get the id, report an error if not given or empty...
00424     bool ok = true;
00425     std::string id = attrs.getStringReporting(SUMO_ATTR_ID, 0, ok);
00426     if (!ok) {
00427         return;
00428     }
00429     if (id[0] == ':') { // internal node
00430         return;
00431     }
00432     SumoXMLNodeType type = NODETYPE_UNKNOWN;
00433     std::string typeS = attrs.getStringReporting(SUMO_ATTR_TYPE, id.c_str(), ok);
00434     if (SUMOXMLDefinitions::NodeTypes.hasString(typeS)) {
00435         type = SUMOXMLDefinitions::NodeTypes.get(typeS);
00436         if (type == NODETYPE_DEAD_END_DEPRECATED) { // patch legacy type
00437             type = NODETYPE_DEAD_END;
00438         }
00439     } else {
00440         WRITE_WARNING("Unknown node type '" + typeS + "' for junction '" + id + "'.");
00441     }
00442     Position pos = readPosition(attrs, id, ok);
00443     NILoader::transformCoordinates(pos, true, myLocation);
00444     // the network may have been built with the option "plain.keep-edge-shape" this
00445     // makes accurate reconstruction of legacy networks impossible. We ought to warn about this
00446     std::string shapeS = attrs.getStringReporting(SUMO_ATTR_SHAPE, id.c_str(), ok, false);
00447     if (shapeS != "") {
00448         PositionVector shape = GeomConvHelper::parseShapeReporting(
00449                                    shapeS, attrs.getObjectType(), id.c_str(), ok, false);
00450         shape.push_back_noDoublePos(shape[0]); // need closed shape
00451         if (!shape.around(pos) && shape.distance(pos) > 1) { // MAGIC_THRESHOLD
00452             // WRITE_WARNING("Junction '" + id + "': distance between pos and shape is " + toString(shape.distance(pos)));
00453             mySuspectKeepShape = true;
00454         }
00455     }
00456     NBNode* node = new NBNode(id, pos, type);
00457     if (!myNodeCont.insert(node)) {
00458         WRITE_ERROR("Problems on adding junction '" + id + "'.");
00459         delete node;
00460         return;
00461     }
00462 }
00463 
00464 
00465 void
00466 NIImporter_SUMO::addSuccEdge(const SUMOSAXAttributes& attrs) {
00467     bool ok = true;
00468     std::string edge_id = attrs.getStringReporting(SUMO_ATTR_EDGE, 0, ok);
00469     myCurrentEdge = 0;
00470     if (myEdges.count(edge_id) == 0) {
00471         WRITE_ERROR("Unknown edge '" + edge_id + "' given in succedge.");
00472         return;
00473     }
00474     myCurrentEdge = myEdges[edge_id];
00475     std::string lane_id = attrs.getStringReporting(SUMO_ATTR_LANE, 0, ok);
00476     myCurrentLane = getLaneAttrsFromID(myCurrentEdge, lane_id);
00477 }
00478 
00479 
00480 void
00481 NIImporter_SUMO::addSuccLane(const SUMOSAXAttributes& attrs) {
00482     if (myCurrentLane == 0) {
00483         WRITE_ERROR("Found succlane outside succ element");
00484         return;
00485     }
00486     bool ok = true;
00487     Connection conn;
00488     std::string laneID = attrs.getStringReporting(SUMO_ATTR_LANE, 0, ok);
00489     if (laneID == "SUMO_NO_DESTINATION") { // legacy check
00490         // deprecated
00491         return;
00492     }
00493     interpretLaneID(laneID, conn.toEdgeID, conn.toLaneIdx);
00494     conn.tlID = attrs.getOptStringReporting(SUMO_ATTR_TLID, 0, ok, "");
00495     conn.mayDefinitelyPass = false; // (attrs.getStringReporting(SUMO_ATTR_STATE, 0, ok, "") == "M");
00496     if (conn.tlID != "") {
00497         conn.tlLinkNo = attrs.hasAttribute(SUMO_ATTR_TLLINKINDEX)
00498                         ? attrs.getIntReporting(SUMO_ATTR_TLLINKINDEX, 0, ok)
00499                         : attrs.getIntReporting(SUMO_ATTR_TLLINKNO__DEPRECATED, 0, ok);
00500     }
00501     myCurrentLane->connections.push_back(conn);
00502 }
00503 
00504 
00505 void
00506 NIImporter_SUMO::addConnection(const SUMOSAXAttributes& attrs) {
00507     bool ok = true;
00508     std::string fromID = attrs.getStringReporting(SUMO_ATTR_FROM, 0, ok);
00509     if (myEdges.count(fromID) == 0) {
00510         WRITE_ERROR("Unknown edge '" + fromID + "' given in connection.");
00511         return;
00512     }
00513     EdgeAttrs* from = myEdges[fromID];
00514     Connection conn;
00515     conn.toEdgeID = attrs.getStringReporting(SUMO_ATTR_TO, 0, ok);
00516     unsigned int fromLaneIdx = attrs.getIntReporting(SUMO_ATTR_FROM_LANE, 0, ok);
00517     conn.toLaneIdx = attrs.getIntReporting(SUMO_ATTR_TO_LANE, 0, ok);
00518     conn.tlID = attrs.getOptStringReporting(SUMO_ATTR_TLID, 0, ok, "");
00519     conn.mayDefinitelyPass = false; // (attrs.getStringReporting(SUMO_ATTR_STATE, 0, ok, "") == "M");
00520     if (conn.tlID != "") {
00521         conn.tlLinkNo = attrs.getIntReporting(SUMO_ATTR_TLLINKINDEX, 0, ok);
00522     }
00523 
00524     if (from->lanes.size() <= (size_t) fromLaneIdx) {
00525         WRITE_ERROR("Invalid lane index '" + toString(fromLaneIdx) + "' for connection from '" + fromID + "'.");
00526         return;
00527     }
00528     from->lanes[fromLaneIdx]->connections.push_back(conn);
00529 }
00530 
00531 
00532 void
00533 NIImporter_SUMO::addProhibition(const SUMOSAXAttributes& attrs) {
00534     bool ok = true;
00535     std::string prohibitor = attrs.getOptStringReporting(SUMO_ATTR_PROHIBITOR, 0, ok, "");
00536     std::string prohibited = attrs.getOptStringReporting(SUMO_ATTR_PROHIBITED, 0, ok, "");
00537     if (!ok) {
00538         return;
00539     }
00540     Prohibition p;
00541     parseProhibitionConnection(prohibitor, p.prohibitorFrom, p.prohibitorTo, ok);
00542     parseProhibitionConnection(prohibited, p.prohibitedFrom, p.prohibitedTo, ok);
00543     if (!ok) {
00544         return;
00545     }
00546     myProhibitions.push_back(p);
00547 }
00548 
00549 
00550 NIImporter_SUMO::LaneAttrs*
00551 NIImporter_SUMO::getLaneAttrsFromID(EdgeAttrs* edge, std::string lane_id) {
00552     std::string edge_id;
00553     unsigned int index;
00554     interpretLaneID(lane_id, edge_id, index);
00555     assert(edge->id == edge_id);
00556     if (edge->lanes.size() <= (size_t) index) {
00557         WRITE_ERROR("Unknown lane '" + lane_id + "' given in succedge.");
00558         return 0;
00559     } else {
00560         return edge->lanes[index];
00561     }
00562 }
00563 
00564 
00565 void
00566 NIImporter_SUMO::interpretLaneID(const std::string& lane_id, std::string& edge_id, unsigned int& index) {
00567     // assume lane_id = edge_id + '_' + index
00568     size_t sep_index = lane_id.rfind('_');
00569     if (sep_index == std::string::npos) {
00570         WRITE_ERROR("Invalid lane id '" + lane_id + "' (missing '_').");
00571     }
00572     edge_id = lane_id.substr(0, sep_index);
00573     std::string index_string = lane_id.substr(sep_index + 1);
00574     try {
00575         index = (unsigned int)TplConvert<char>::_2int(index_string.c_str());
00576     } catch (NumberFormatException) {
00577         WRITE_ERROR("Invalid lane index '" + index_string + "' for lane '" + lane_id + "'.");
00578     }
00579 }
00580 
00581 
00582 NBLoadedSUMOTLDef*
00583 NIImporter_SUMO::initTrafficLightLogic(const SUMOSAXAttributes& attrs, NBLoadedSUMOTLDef* currentTL) {
00584     if (currentTL) {
00585         WRITE_ERROR("Definition of tl-logic '" + currentTL->getID() + "' was not finished.");
00586         return 0;
00587     }
00588     bool ok = true;
00589     std::string id = attrs.getStringReporting(SUMO_ATTR_ID, 0, ok);
00590     SUMOTime offset = TIME2STEPS(attrs.getSUMORealReporting(SUMO_ATTR_OFFSET, id.c_str(), ok));
00591     std::string programID = attrs.getOptStringReporting(SUMO_ATTR_PROGRAMID, id.c_str(), ok, "<unknown>");
00592     std::string type = attrs.getStringReporting(SUMO_ATTR_TYPE, 0, ok);
00593     if (type != toString(TLTYPE_STATIC)) {
00594         WRITE_WARNING("Traffic light '" + id + "' has unsupported type '" + type + "' and will be converted to '" +
00595                       toString(TLTYPE_STATIC) + "'");
00596     }
00597     if (ok) {
00598         return new NBLoadedSUMOTLDef(id, programID, offset);
00599     } else {
00600         return 0;
00601     }
00602 }
00603 
00604 
00605 void
00606 NIImporter_SUMO::addPhase(const SUMOSAXAttributes& attrs, NBLoadedSUMOTLDef* currentTL) {
00607     if (!currentTL) {
00608         WRITE_ERROR("found phase without tl-logic");
00609         return;
00610     }
00611     const std::string& id = currentTL->getID();
00612     bool ok = true;
00613     std::string state = attrs.getStringReporting(SUMO_ATTR_STATE, id.c_str(), ok);
00614     SUMOTime duration = TIME2STEPS(attrs.getSUMORealReporting(SUMO_ATTR_DURATION, id.c_str(), ok));
00615     if (duration < 0) {
00616         WRITE_ERROR("Phase duration for tl-logic '" + id + "/" + currentTL->getProgramID() + "' must be positive.");
00617         return;
00618     }
00619     // if the traffic light is an actuated traffic light, try to get
00620     //  the minimum and maximum durations
00621     //SUMOTime minDuration = attrs.getOptSUMOTimeReporting(SUMO_ATTR_MINDURATION, id.c_str(), ok, -1);
00622     //SUMOTime maxDuration = attrs.getOptSUMOTimeReporting(SUMO_ATTR_MAXDURATION, id.c_str(), ok, -1);
00623     if (ok) {
00624         currentTL->addPhase(duration, state);
00625     }
00626 }
00627 
00628 
00629 PositionVector
00630 NIImporter_SUMO::reconstructEdgeShape(const EdgeAttrs* edge, const Position& from, const Position& to) {
00631     const PositionVector& firstLane = edge->lanes[0]->shape;
00632     PositionVector result;
00633     result.push_back(from);
00634 
00635     // reverse logic of NBEdge::computeLaneShape
00636     // !!! this will only work for old-style constant width lanes
00637     const size_t noLanes = edge->lanes.size();
00638     for (unsigned int i = 1; i < firstLane.size() - 1; i++) {
00639         Position from = firstLane[i - 1];
00640         Position me = firstLane[i];
00641         Position to = firstLane[i + 1];
00642         std::pair<SUMOReal, SUMOReal> offsets = NBEdge::laneOffset(
00643                 from, me, SUMO_const_laneWidthAndOffset, (unsigned int)noLanes - 1,
00644                 noLanes, edge->lsf, false);
00645         std::pair<SUMOReal, SUMOReal> offsets2 = NBEdge::laneOffset(
00646                     me, to, SUMO_const_laneWidthAndOffset, (unsigned int)noLanes - 1,
00647                     noLanes, edge->lsf, false);
00648 
00649         Line l1(
00650             Position(from.x() + offsets.first, from.y() + offsets.second),
00651             Position(me.x() + offsets.first, me.y() + offsets.second));
00652         l1.extrapolateBy(100);
00653         Line l2(
00654             Position(me.x() + offsets2.first, me.y() + offsets2.second),
00655             Position(to.x() + offsets2.first, to.y() + offsets2.second));
00656         l2.extrapolateBy(100);
00657         if (l1.intersects(l2)) {
00658             result.push_back(l1.intersectsAt(l2));
00659         } else {
00660             WRITE_WARNING("Could not reconstruct shape for edge '" + edge->id + "'.");
00661         }
00662     }
00663 
00664     result.push_back(to);
00665     return result;
00666 }
00667 
00668 
00669 GeoConvHelper*
00670 NIImporter_SUMO::loadLocation(const SUMOSAXAttributes& attrs) {
00671     // @todo refactor parsing of location since its duplicated in NLHandler and PCNetProjectionLoader
00672     bool ok = true;
00673     GeoConvHelper* result = 0;
00674     PositionVector s = GeomConvHelper::parseShapeReporting(
00675                            attrs.getStringReporting(SUMO_ATTR_NET_OFFSET, 0, ok),
00676                            attrs.getObjectType(), 0, ok, false);
00677     Boundary convBoundary = GeomConvHelper::parseBoundaryReporting(
00678                                 attrs.getStringReporting(SUMO_ATTR_CONV_BOUNDARY, 0, ok),
00679                                 attrs.getObjectType(), 0, ok);
00680     Boundary origBoundary = GeomConvHelper::parseBoundaryReporting(
00681                                 attrs.getStringReporting(SUMO_ATTR_ORIG_BOUNDARY, 0, ok),
00682                                 attrs.getObjectType(), 0, ok);
00683     std::string proj = attrs.getStringReporting(SUMO_ATTR_ORIG_PROJ, 0, ok);
00684     if (ok) {
00685         Position networkOffset = s[0];
00686         result = new GeoConvHelper(proj, networkOffset, origBoundary, convBoundary);
00687         GeoConvHelper::setLoaded(*result);
00688     }
00689     return result;
00690 }
00691 
00692 
00693 Position
00694 NIImporter_SUMO::readPosition(const SUMOSAXAttributes& attrs, const std::string& id, bool& ok) {
00695     SUMOReal x = attrs.getSUMORealReporting(SUMO_ATTR_X, id.c_str(), ok);
00696     SUMOReal y = attrs.getSUMORealReporting(SUMO_ATTR_Y, id.c_str(), ok);
00697     SUMOReal z = 0;
00698     if (attrs.hasAttribute(SUMO_ATTR_Z)) {
00699         z = attrs.getSUMORealReporting(SUMO_ATTR_Z, id.c_str(), ok);
00700     }
00701     return Position(x, y, z);
00702 }
00703 
00704 
00705 void
00706 NIImporter_SUMO::parseProhibitionConnection(const std::string& attr, std::string& from, std::string& to, bool& ok) {
00707     // split from/to
00708     size_t div = attr.find("->");
00709     if (div == std::string::npos) {
00710         WRITE_ERROR("Missing connection divider in prohibition attribute '" + attr + "'");
00711         ok = false;
00712     }
00713     from = attr.substr(0, div);
00714     to = attr.substr(div + 2);
00715     // check whether the definition includes a lane information and discard it
00716     if (from.find('_') != std::string::npos) {
00717         from = from.substr(0, from.find('_'));
00718     }
00719     if (to.find('_') != std::string::npos) {
00720         to = to.substr(0, to.find('_'));
00721     }
00722     // check whether the edges are known
00723     if (myEdges.count(from) == 0) {
00724         WRITE_ERROR("Unknown edge prohibition '" + from + "'");
00725         ok = false;
00726     }
00727     if (myEdges.count(to) == 0) {
00728         WRITE_ERROR("Unknown edge prohibition '" + to + "'");
00729         ok = false;
00730     }
00731 }
00732 /****************************************************************************/
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Defines