SUMO - Simulation of Urban MObility

NIImporter_OpenStreetMap.cpp

Go to the documentation of this file.
00001 /****************************************************************************/
00010 // Importer for networks stored in OpenStreetMap format
00011 /****************************************************************************/
00012 // SUMO, Simulation of Urban MObility; see http://sumo.sourceforge.net/
00013 // Copyright (C) 2001-2012 DLR (http://www.dlr.de/) and contributors
00014 /****************************************************************************/
00015 //
00016 //   This file is part of SUMO.
00017 //   SUMO is free software: you can redistribute it and/or modify
00018 //   it under the terms of the GNU General Public License as published by
00019 //   the Free Software Foundation, either version 3 of the License, or
00020 //   (at your option) any later version.
00021 //
00022 /****************************************************************************/
00023 
00024 
00025 // ===========================================================================
00026 // included modules
00027 // ===========================================================================
00028 #ifdef _MSC_VER
00029 #include <windows_config.h>
00030 #else
00031 #include <config.h>
00032 #endif
00033 #include <algorithm>
00034 #include <set>
00035 #include <functional>
00036 #include <sstream>
00037 #include <limits>
00038 #include <utils/xml/SUMOSAXHandler.h>
00039 #include <utils/common/UtilExceptions.h>
00040 #include <utils/common/TplConvert.h>
00041 #include <utils/common/ToString.h>
00042 #include <utils/common/MsgHandler.h>
00043 #include <utils/common/StringUtils.h>
00044 #include <utils/common/StringTokenizer.h>
00045 #include <netbuild/NBEdge.h>
00046 #include <netbuild/NBEdgeCont.h>
00047 #include <netbuild/NBNode.h>
00048 #include <netbuild/NBNodeCont.h>
00049 #include <netbuild/NBNetBuilder.h>
00050 #include <netbuild/NBOwnTLDef.h>
00051 #include <utils/xml/SUMOXMLDefinitions.h>
00052 #include <utils/geom/GeoConvHelper.h>
00053 #include <utils/geom/GeomConvHelper.h>
00054 #include <utils/options/OptionsCont.h>
00055 #include <utils/common/FileHelpers.h>
00056 #include <utils/xml/XMLSubSys.h>
00057 #include "NILoader.h"
00058 #include "NIImporter_OpenStreetMap.h"
00059 
00060 #ifdef CHECK_MEMORY_LEAKS
00061 #include <foreign/nvwa/debug_new.h>
00062 #endif // CHECK_MEMORY_LEAKS
00063 
00064 // ---------------------------------------------------------------------------
00065 // static members
00066 // ---------------------------------------------------------------------------
00067 const SUMOReal NIImporter_OpenStreetMap::MAXSPEED_UNGIVEN = -1;
00068 
00069 
00070 // ===========================================================================
00071 // Private classes
00072 // ===========================================================================
00073 
00076 class NIImporter_OpenStreetMap::CompareEdges {
00077 public:
00078     bool operator()(const Edge* e1, const Edge* e2) const {
00079         if (e1->myHighWayType != e2->myHighWayType) {
00080             return e1->myHighWayType > e2->myHighWayType;
00081         }
00082         if (e1->myNoLanes != e2->myNoLanes) {
00083             return e1->myNoLanes > e2->myNoLanes;
00084         }
00085         if (e1->myMaxSpeed != e2->myMaxSpeed) {
00086             return e1->myMaxSpeed > e2->myMaxSpeed;
00087         }
00088         if (e1->myIsOneWay != e2->myIsOneWay) {
00089             return e1->myIsOneWay > e2->myIsOneWay;
00090         }
00091         return e1->myCurrentNodes > e2->myCurrentNodes;
00092     }
00093 };
00094 
00095 // ===========================================================================
00096 // method definitions
00097 // ===========================================================================
00098 // ---------------------------------------------------------------------------
00099 // static methods
00100 // ---------------------------------------------------------------------------
00101 const std::string NIImporter_OpenStreetMap::compoundTypeSeparator("|");
00102 
00103 
00104 void
00105 NIImporter_OpenStreetMap::loadNetwork(const OptionsCont& oc, NBNetBuilder& nb) {
00106     NIImporter_OpenStreetMap importer;
00107     importer._loadNetwork(oc, nb);
00108 }
00109 
00110 
00111 NIImporter_OpenStreetMap::NIImporter_OpenStreetMap() {}
00112 
00113 
00114 NIImporter_OpenStreetMap::~NIImporter_OpenStreetMap() {
00115     // delete nodes
00116     for (std::set<NIOSMNode*, CompareNodes>::iterator i = myUniqueNodes.begin(); i != myUniqueNodes.end(); i++) {
00117         delete *i;
00118     }
00119     // delete edges
00120     for (std::map<std::string, Edge*>::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
00121         delete(*i).second;
00122     }
00123 }
00124 
00125 
00126 void
00127 NIImporter_OpenStreetMap::_loadNetwork(const OptionsCont& oc, NBNetBuilder& nb) {
00128     // check whether the option is set (properly)
00129     if (!oc.isSet("osm-files")) {
00130         return;
00131     }
00132     // preset types
00133     //  for highways
00134     NBTypeCont& tc = nb.getTypeCont();
00135     SUMOReal const WIDTH = NBEdge::UNSPECIFIED_WIDTH;
00136     tc.insert("highway.motorway",      3, (SUMOReal)(160./ 3.6), 13, WIDTH, SVC_UNKNOWN, true);
00137     tc.insert("highway.motorway_link", 1, (SUMOReal)(80. / 3.6), 12, WIDTH, SVC_UNKNOWN, true);
00138     tc.insert("highway.trunk",         2, (SUMOReal)(100./ 3.6), 11, WIDTH); // !!! 130km/h?
00139     tc.insert("highway.trunk_link",    1, (SUMOReal)(80. / 3.6), 10, WIDTH);
00140     tc.insert("highway.primary",       2, (SUMOReal)(100./ 3.6),  9, WIDTH);
00141     tc.insert("highway.primary_link",  1, (SUMOReal)(80. / 3.6),  8, WIDTH);
00142     tc.insert("highway.secondary",     2, (SUMOReal)(100./ 3.6),  7, WIDTH);
00143     tc.insert("highway.secondary_link",1, (SUMOReal)(80. / 3.6),  6, WIDTH);
00144     tc.insert("highway.tertiary",      1, (SUMOReal)(80. / 3.6),  6, WIDTH);
00145     tc.insert("highway.tertiary_link", 1, (SUMOReal)(80. / 3.6),  5, WIDTH);
00146     tc.insert("highway.unclassified",  1, (SUMOReal)(80. / 3.6),  5, WIDTH);
00147     tc.insert("highway.residential",   1, (SUMOReal)(50. / 3.6),  4, WIDTH); // actually, maybe one lane for parking would be nice...
00148     tc.insert("highway.living_street", 1, (SUMOReal)(10. / 3.6),  3, WIDTH);
00149     tc.insert("highway.service",       1, (SUMOReal)(20. / 3.6),  2, WIDTH, SVC_DELIVERY);
00150     tc.insert("highway.track",         1, (SUMOReal)(20. / 3.6),  1, WIDTH);
00151     tc.insert("highway.services",      1, (SUMOReal)(30. / 3.6),  1, WIDTH);
00152     tc.insert("highway.unsurfaced",    1, (SUMOReal)(30. / 3.6),  1, WIDTH); // unofficial value, used outside germany
00153     tc.insert("highway.footway",       1, (SUMOReal)(30. / 3.6),  1, WIDTH, SVC_PEDESTRIAN); 
00154     tc.insert("highway.pedestrian",    1, (SUMOReal)(30. / 3.6),  1, WIDTH, SVC_PEDESTRIAN);
00155 
00156     tc.insert("highway.path",          1, (SUMOReal)(10. / 3.6),  1, WIDTH, SVC_PEDESTRIAN);
00157     tc.insert("highway.bridleway",     1, (SUMOReal)(10. / 3.6),  1, WIDTH, SVC_BICYCLE); // no horse stuff
00158     tc.insert("highway.cycleway",      1, (SUMOReal)(20. / 3.6),  1, WIDTH, SVC_BICYCLE);
00159     tc.insert("highway.footway",       1, (SUMOReal)(10. / 3.6),  1, WIDTH, SVC_PEDESTRIAN);
00160     tc.insert("highway.step",          1, (SUMOReal)(5.  / 3.6),  1, WIDTH, SVC_PEDESTRIAN); // additional
00161     tc.insert("highway.steps",         1, (SUMOReal)(5.  / 3.6),  1, WIDTH, SVC_PEDESTRIAN); // :-) do not run too fast
00162     tc.insert("highway.stairs",        1, (SUMOReal)(5.  / 3.6),  1, WIDTH, SVC_PEDESTRIAN); // additional
00163     tc.insert("highway.bus_guideway",  1, (SUMOReal)(30. / 3.6),  1, WIDTH, SVC_BUS);
00164     tc.insert("highway.raceway",       2, (SUMOReal)(300./ 3.6), 14, WIDTH, SVC_VIP);
00165     tc.insert("highway.ford",          1, (SUMOReal)(10. / 3.6),  1, WIDTH, SVC_PUBLIC_ARMY);
00166 
00167     //  for railways
00168     tc.insert("railway.rail",          1, (SUMOReal)(30. / 3.6),  1, WIDTH, SVC_RAIL_FAST);
00169     tc.insert("railway.tram",          1, (SUMOReal)(30. / 3.6),  1, WIDTH, SVC_CITYRAIL);
00170     tc.insert("railway.light_rail",    1, (SUMOReal)(30. / 3.6),  1, WIDTH, SVC_LIGHTRAIL);
00171     tc.insert("railway.subway",        1, (SUMOReal)(30. / 3.6),  1, WIDTH, SVC_CITYRAIL);
00172     tc.insert("railway.preserved",     1, (SUMOReal)(30. / 3.6),  1, WIDTH, SVC_LIGHTRAIL);
00173     tc.insert("railway.monorail",      1, (SUMOReal)(30. / 3.6),  1, WIDTH, SVC_LIGHTRAIL); // rail stuff has to be discussed
00174 
00175 
00176     /* Parse file(s)
00177      * Each file is parsed twice: first for nodes, second for edges. */
00178     std::vector<std::string> files = oc.getStringVector("osm-files");
00179     // load nodes, first
00180     NodesHandler nodesHandler(myOSMNodes, myUniqueNodes);
00181     for (std::vector<std::string>::const_iterator file = files.begin(); file != files.end(); ++file) {
00182         // nodes
00183         if (!FileHelpers::exists(*file)) {
00184             WRITE_ERROR("Could not open osm-file '" + *file + "'.");
00185             return;
00186         }
00187         nodesHandler.setFileName(*file);
00188         PROGRESS_BEGIN_MESSAGE("Parsing nodes from osm-file '" + *file + "'");
00189         if (!XMLSubSys::runParser(nodesHandler, *file)) {
00190             return;
00191         }
00192         PROGRESS_DONE_MESSAGE();
00193     }
00194     // load edges, then
00195     EdgesHandler edgesHandler(myOSMNodes, myEdges);
00196     for (std::vector<std::string>::const_iterator file = files.begin(); file != files.end(); ++file) {
00197         // edges
00198         edgesHandler.setFileName(*file);
00199         PROGRESS_BEGIN_MESSAGE("Parsing edges from osm-file '" + *file + "'");
00200         XMLSubSys::runParser(edgesHandler, *file);
00201         PROGRESS_DONE_MESSAGE();
00202     }
00203 
00204     /* Remove duplicate edges with the same shape and attributes */
00205     if (!OptionsCont::getOptions().getBool("osm.skip-duplicates-check")) {
00206         PROGRESS_BEGIN_MESSAGE("Removing duplicate edges");
00207         if (myEdges.size() > 1) {
00208             std::set<const Edge*, CompareEdges> dupsFinder;
00209             for (std::map<std::string, Edge*>::iterator it = myEdges.begin(); it != myEdges.end();) {
00210                 if (dupsFinder.count(it->second) > 0) {
00211                     WRITE_MESSAGE("Found duplicate edges. Removing " + it->first);
00212                     delete it->second;
00213                     myEdges.erase(it++);
00214                 } else {
00215                     dupsFinder.insert(it->second);
00216                     it++;
00217                 }
00218             }
00219         }
00220         PROGRESS_DONE_MESSAGE();
00221     }
00222 
00223     /* Mark which nodes are used (by edges or traffic lights).
00224      * This is necessary to detect which OpenStreetMap nodes are for
00225      * geometry only */
00226     std::map<int, int> nodeUsage;
00227     // Mark which nodes are used by edges (begin and end)
00228     for (std::map<std::string, Edge*>::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
00229         Edge* e = (*i).second;
00230         assert(e->myCurrentIsRoad);
00231         for (std::vector<int>::const_iterator j = e->myCurrentNodes.begin(); j != e->myCurrentNodes.end(); ++j) {
00232             if (nodeUsage.find(*j) == nodeUsage.end()) {
00233                 nodeUsage[*j] = 0;
00234             }
00235             nodeUsage[*j] = nodeUsage[*j] + 1;
00236         }
00237     }
00238     // Mark which nodes are used by traffic lights
00239     for (std::map<int, NIOSMNode*>::const_iterator nodesIt = myOSMNodes.begin(); nodesIt != myOSMNodes.end(); ++nodesIt) {
00240         if (nodesIt->second->tlsControlled) {
00241             // If the key is not found in the map, the value is automatically
00242             // initialized with 0.
00243             nodeUsage[nodesIt->first] += 1;
00244         }
00245     }
00246     /* Instantiate edges
00247      * Only those nodes in the middle of an edge which are used by more than
00248      * one edge are instantiated. Other nodes are considered as geometry nodes. */
00249     NBNodeCont& nc = nb.getNodeCont();
00250     NBEdgeCont& ec = nb.getEdgeCont();
00251     NBTrafficLightLogicCont& tlsc = nb.getTLLogicCont();
00252     for (std::map<std::string, Edge*>::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
00253         Edge* e = (*i).second;
00254         assert(e->myCurrentIsRoad);
00255         // build nodes;
00256         //  the from- and to-nodes must be built in any case
00257         //  the geometry nodes are only built if more than one edge references them
00258         NBNode* currentFrom = insertNodeChecking(*e->myCurrentNodes.begin(), nc, tlsc);
00259         NBNode* last = insertNodeChecking(*(e->myCurrentNodes.end() - 1), nc, tlsc);
00260         int running = 0;
00261         std::vector<int> passed;
00262         for (std::vector<int>::iterator j = e->myCurrentNodes.begin(); j != e->myCurrentNodes.end(); ++j) {
00263             passed.push_back(*j);
00264             if (nodeUsage[*j] > 1 && j != e->myCurrentNodes.end() - 1 && j != e->myCurrentNodes.begin()) {
00265                 NBNode* currentTo = insertNodeChecking(*j, nc, tlsc);
00266                 insertEdge(e, running, currentFrom, currentTo, passed, ec, tc);
00267                 currentFrom = currentTo;
00268                 running++;
00269                 passed.clear();
00270             }
00271         }
00272         if (running == 0) {
00273             running = -1;
00274         }
00275         insertEdge(e, running, currentFrom, last, passed, ec, tc);
00276     }
00277 }
00278 
00279 
00280 NBNode*
00281 NIImporter_OpenStreetMap::insertNodeChecking(int id, NBNodeCont& nc, NBTrafficLightLogicCont& tlsc) {
00282     NBNode* from = nc.retrieve(toString(id));
00283     if (from == 0) {
00284         NIOSMNode* n = myOSMNodes.find(id)->second;
00285         Position pos(n->lon, n->lat);
00286         if (!NILoader::transformCoordinates(pos, true)) {
00287             WRITE_ERROR("Unable to project coordinates for node " + toString(id) + ".");
00288             delete from;
00289             return 0;
00290         }
00291         from = new NBNode(toString(id), pos);
00292         if (!nc.insert(from)) {
00293             WRITE_ERROR("Could not insert node '" + toString(id) + "').");
00294             delete from;
00295             return 0;
00296         }
00297         if (n->tlsControlled) {
00298             // ok, this node is a traffic light node where no other nodes
00299             //  participate
00300             NBOwnTLDef* tlDef = new NBOwnTLDef(toString(id), from);
00301             if (!tlsc.insert(tlDef)) {
00302                 // actually, nothing should fail here
00303                 delete tlDef;
00304                 throw ProcessError("Could not allocate tls '" + toString(id) + "'.");
00305             }
00306         }
00307     }
00308     return from;
00309 }
00310 
00311 
00312 void
00313 NIImporter_OpenStreetMap::insertEdge(Edge* e, int index, NBNode* from, NBNode* to,
00314                                      const std::vector<int> &passed, NBEdgeCont& ec, NBTypeCont& tc) {
00315     // patch the id
00316     std::string id = e->id;
00317     if (index >= 0) {
00318         id = id + "#" + toString(index);
00319     }
00320     // convert the shape
00321     PositionVector shape;
00322     for (std::vector<int>::const_iterator i = passed.begin(); i != passed.end(); ++i) {
00323         NIOSMNode* n = myOSMNodes.find(*i)->second;
00324         Position pos(n->lon, n->lat);
00325         if (!NILoader::transformCoordinates(pos, true)) {
00326             throw ProcessError("Unable to project coordinates for edge " + id + ".");
00327         }
00328         shape.push_back_noDoublePos(pos);
00329     }
00330 
00331     std::string type = e->myHighWayType;
00332     if (!tc.knows(type)) {
00333         if (type.find(compoundTypeSeparator) != std::string::npos) {
00334             // this edge has a combination type which does not yet exist in the TypeContainer
00335             StringTokenizer tok = StringTokenizer(type, compoundTypeSeparator);
00336             std::set<std::string> types;
00337             while (tok.hasNext()) {
00338                 std::string t = tok.next();
00339                 if (tc.knows(t)) {
00340                     types.insert(t);
00341                 } else {
00342                     WRITE_WARNING("Discarding edge " + id + " with type \"" + type + "\" (unknown compound \"" + t + "\").");
00343                     return;
00344                 }
00345             }
00346 
00347             if (types.size() == 2 &&
00348                     types.count("railway.tram") == 1) {
00349                 // compound types concern mostly the special case of tram tracks on a normal road.
00350                 // in this case we simply discard the tram information since the default for road is to allow all vclasses
00351                 types.erase("railway.tram");
00352                 std::string otherCompound = *(types.begin());
00353                 // XXX if otherCompound does not allow all vehicles (e.g. SVC_DELIVERY), tram will still not be allowed
00354                 type = otherCompound;
00355             } else {
00356                 // other cases not implemented yet
00357                 WRITE_WARNING("Discarding edge " + id + " with unknown type \"" + type + "\".");
00358                 return;
00359             }
00360         } else {
00361             // we do not know the type -> something else, ignore
00362             //WRITE_WARNING("Discarding edge " + id + " with unknown type \"" + type + "\".");
00363             return;
00364         }
00365     }
00366 
00367 
00368 
00369     // otherwise it is not an edge and will be ignored
00370     int noLanes = tc.getNumLanes(type);
00371     SUMOReal speed = tc.getSpeed(type);
00372     bool defaultsToOneWay = tc.getIsOneWay(type);
00373     SUMOVehicleClasses allowedClasses = tc.getAllowedClasses(type);
00374     SUMOVehicleClasses disallowedClasses = tc.getDisallowedClasses(type);
00375     // check directions
00376     bool addSecond = true;
00377     if (e->myIsOneWay == "true" || e->myIsOneWay == "yes" || e->myIsOneWay == "1" || (defaultsToOneWay && e->myIsOneWay != "no" && e->myIsOneWay != "false" && e->myIsOneWay != "0")) {
00378         addSecond = false;
00379     }
00380     // if we had been able to extract the number of lanes, override the highway type default
00381     if (e->myNoLanes >= 0) {
00382         if (!addSecond) {
00383             noLanes = e->myNoLanes;
00384         } else {
00385             noLanes = e->myNoLanes / 2;
00386         }
00387     }
00388     // if we had been able to extract the maximum speed, override the type's default
00389     if (e->myMaxSpeed != MAXSPEED_UNGIVEN) {
00390         speed = (SUMOReal)(e->myMaxSpeed / 3.6);
00391     }
00392 
00393     if (noLanes != 0 && speed != 0) {
00394         if (e->myIsOneWay != "" && e->myIsOneWay != "false" && e->myIsOneWay != "no" && e->myIsOneWay != "true" && e->myIsOneWay != "yes" && e->myIsOneWay != "-1" && e->myIsOneWay != "1") {
00395             WRITE_WARNING("New value for oneway found: " + e->myIsOneWay);
00396         }
00397         LaneSpreadFunction lsf = addSecond ? LANESPREAD_RIGHT : LANESPREAD_CENTER;
00398         if (e->myIsOneWay != "-1") {
00399             NBEdge* nbe = new NBEdge(id, from, to, type, speed, noLanes, tc.getPriority(type),
00400                                      tc.getWidth(type), NBEdge::UNSPECIFIED_OFFSET, shape, e->streetName, lsf);
00401             nbe->setVehicleClasses(allowedClasses, disallowedClasses);
00402             if (!ec.insert(nbe)) {
00403                 delete nbe;
00404                 throw ProcessError("Could not add edge '" + id + "'.");
00405             }
00406         }
00407         if (addSecond) {
00408             if (e->myIsOneWay != "-1") {
00409                 id = "-" + id;
00410             }
00411             NBEdge* nbe = new NBEdge(id, to, from, type, speed, noLanes, tc.getPriority(type),
00412                                      tc.getWidth(type), NBEdge::UNSPECIFIED_OFFSET, shape.reverse(), e->streetName, lsf);
00413             nbe->setVehicleClasses(allowedClasses, disallowedClasses);
00414             if (!ec.insert(nbe)) {
00415                 delete nbe;
00416                 throw ProcessError("Could not add edge '-" + id + "'.");
00417             }
00418         }
00419     }
00420 }
00421 
00422 
00423 // ---------------------------------------------------------------------------
00424 // definitions of NIImporter_OpenStreetMap::NodesHandler-methods
00425 // ---------------------------------------------------------------------------
00426 NIImporter_OpenStreetMap::NodesHandler::NodesHandler(
00427         std::map<int, NIOSMNode*> &toFill,
00428         std::set<NIOSMNode*, CompareNodes> &uniqueNodes) : 
00429     SUMOSAXHandler("osm - file"), 
00430     myToFill(toFill), 
00431     myUniqueNodes(uniqueNodes),
00432     myLastNodeID(-1), 
00433     myIsInValidNodeTag(false), 
00434     myHierarchyLevel(0) {
00435 }
00436 
00437 
00438 NIImporter_OpenStreetMap::NodesHandler::~NodesHandler() {}
00439 
00440 
00441 void
00442 NIImporter_OpenStreetMap::NodesHandler::myStartElement(int element, const SUMOSAXAttributes& attrs) {
00443     ++myHierarchyLevel;
00444     if (element == SUMO_TAG_NODE) {
00445         bool ok = true;
00446         if (myHierarchyLevel != 2) {
00447             WRITE_ERROR("Node element on wrong XML hierarchy level (id='" + toString(attrs.getIntReporting(SUMO_ATTR_ID, 0, ok)) + "', level='" + toString(myHierarchyLevel) + "').");
00448             return;
00449         }
00450         int id = attrs.getIntReporting(SUMO_ATTR_ID, 0, ok);
00451         std::string action = attrs.hasAttribute("action") ? attrs.getStringSecure("action", "") : "";
00452         if (action == "delete") {
00453             return;
00454         }
00455         if (!ok) {
00456             return;
00457         }
00458         myLastNodeID = -1;
00459         if (myToFill.find(id) == myToFill.end()) {
00460             myLastNodeID = id;
00461             // assume we are loading multiple files...
00462             //  ... so we won't report duplicate nodes
00463             bool ok = true;
00464             double tlat, tlon;
00465             std::istringstream lon(attrs.getStringReporting(SUMO_ATTR_LON, toString(id).c_str(), ok));
00466             if (!ok) {
00467                 return;
00468             }
00469             lon >> tlon;
00470             if (lon.fail()) {
00471                 WRITE_ERROR("Node's '" + toString(id) + "' lon information is not numeric.");
00472                 return;
00473             }
00474             std::istringstream lat(attrs.getStringReporting(SUMO_ATTR_LAT, toString(id).c_str(), ok));
00475             if (!ok) {
00476                 return;
00477             }
00478             lat >> tlat;
00479             if (lat.fail()) {
00480                 WRITE_ERROR("Node's '" + toString(id) + "' lat information is not numeric.");
00481                 return;
00482             }
00483             NIOSMNode* toAdd = new NIOSMNode();
00484             toAdd->id = id;
00485             toAdd->tlsControlled = false;
00486             toAdd->lat = tlat;
00487             toAdd->lon = tlon;
00488             myIsInValidNodeTag = true;
00489 
00490             std::set<NIOSMNode*, CompareNodes>::iterator similarNode = myUniqueNodes.find(toAdd);
00491             if (similarNode == myUniqueNodes.end()) {
00492                 myUniqueNodes.insert(toAdd);
00493             } else {
00494                 delete toAdd;
00495                 toAdd = *similarNode; 
00496                 WRITE_MESSAGE("Found duplicate nodes. Substituting " + toString(id) + " with " + toString(toAdd->id));
00497             }
00498             myToFill[id] = toAdd;
00499         }
00500     }
00501     if (element == SUMO_TAG_TAG && myIsInValidNodeTag) {
00502         if (myHierarchyLevel != 3) {
00503             WRITE_ERROR("Tag element on wrong XML hierarchy level.");
00504             return;
00505         }
00506         bool ok = true;
00507         std::string key = attrs.getStringReporting(SUMO_ATTR_K, toString(myLastNodeID).c_str(), ok);
00508         std::string value = attrs.getOptStringReporting(SUMO_ATTR_V, toString(myLastNodeID).c_str(), ok, "");
00509         if (!ok) {
00510             return;
00511         }
00512         if (key == "highway" && value.find("traffic_signal") != std::string::npos &&
00513                 !OptionsCont::getOptions().getBool("osm.discard-tls")) {
00514             myToFill[myLastNodeID]->tlsControlled = true;
00515         }
00516     }
00517 }
00518 
00519 
00520 void
00521 NIImporter_OpenStreetMap::NodesHandler::myEndElement(int element) {
00522     if (element == SUMO_TAG_NODE && myHierarchyLevel == 2) {
00523         myLastNodeID = -1;
00524         myIsInValidNodeTag = false;
00525     }
00526     --myHierarchyLevel;
00527 }
00528 
00529 
00530 // ---------------------------------------------------------------------------
00531 // definitions of NIImporter_OpenStreetMap::EdgesHandler-methods
00532 // ---------------------------------------------------------------------------
00533 NIImporter_OpenStreetMap::EdgesHandler::EdgesHandler(
00534     const std::map<int, NIOSMNode*> &osmNodes,
00535     std::map<std::string, Edge*> &toFill)
00536     : SUMOSAXHandler("osm - file"),
00537       myOSMNodes(osmNodes), myEdgeMap(toFill) {
00538     mySpeedMap["signals"] = MAXSPEED_UNGIVEN;
00539     mySpeedMap["none"] = 300.;
00540     mySpeedMap["no"] = 300.;
00541     mySpeedMap["walk"] = 5.;
00542     mySpeedMap["DE:rural"] = 100.;
00543     mySpeedMap["DE:urban"] = 50.;
00544     mySpeedMap["DE:living_street"] = 10.;
00545 
00546 }
00547 
00548 
00549 NIImporter_OpenStreetMap::EdgesHandler::~EdgesHandler() {
00550 }
00551 
00552 
00553 void
00554 NIImporter_OpenStreetMap::EdgesHandler::myStartElement(int element,
00555         const SUMOSAXAttributes& attrs) {
00556     myParentElements.push_back(element);
00557     // parse "way" elements
00558     if (element == SUMO_TAG_WAY) {
00559         bool ok = true;
00560         std::string id = attrs.getStringReporting(SUMO_ATTR_ID, 0, ok);
00561         std::string action = attrs.hasAttribute("action") ? attrs.getStringSecure("action", "") : "";
00562         if (action == "delete") {
00563             myCurrentEdge = 0;
00564             return;
00565         }
00566         if (!ok) {
00567             myCurrentEdge = 0;
00568             return;
00569         }
00570         myCurrentEdge = new Edge();
00571         myCurrentEdge->id = id;
00572         myCurrentEdge->myNoLanes = -1;
00573         myCurrentEdge->myMaxSpeed = MAXSPEED_UNGIVEN;
00574         myCurrentEdge->myCurrentIsRoad = false;
00575     }
00576     // parse "nd" (node) elements
00577     if (element == SUMO_TAG_ND) {
00578         bool ok = true;
00579         int ref = attrs.getIntReporting(SUMO_ATTR_REF, 0, ok);
00580         if (ok) {
00581             std::map<int, NIOSMNode*>::const_iterator node = myOSMNodes.find(ref);
00582             if (node == myOSMNodes.end()) {
00583                 WRITE_WARNING("The referenced geometry information (ref='" + toString(ref) + "') is not known");
00584                 return;
00585             } else {
00586                 ref = node->second->id; // node may have been substituted
00587                 if (myCurrentEdge->myCurrentNodes.size() == 0 ||
00588                         myCurrentEdge->myCurrentNodes.back() != ref) { // avoid consecutive duplicates
00589                     myCurrentEdge->myCurrentNodes.push_back(ref); 
00590                 }
00591             }
00592         }
00593     }
00594     // parse values
00595     if (element == SUMO_TAG_TAG && myParentElements.size() > 2 && myParentElements[myParentElements.size() - 2] == SUMO_TAG_WAY) {
00596         if (myCurrentEdge == 0) {
00597             return;
00598         }
00599         bool ok = true;
00600         std::string key = attrs.getStringReporting(SUMO_ATTR_K, toString(myCurrentEdge->id).c_str(), ok);
00601         std::string value = attrs.getStringReporting(SUMO_ATTR_V, toString(myCurrentEdge->id).c_str(), ok);
00602         if (!ok) {
00603             return;
00604         }
00605         if (key == "highway" || key == "railway") {
00606             if (myCurrentEdge->myHighWayType != "") {
00607                 // osm-ways may be used by more than one mode (eg railway.tram + highway.residential. this is relevant for multimodal traffic)
00608                 // we create a new type for this kind of situation which must then be resolved in insertEdge()
00609                 myCurrentEdge->myHighWayType = myCurrentEdge->myHighWayType + compoundTypeSeparator + key + "." + value;
00610             } else {
00611                 myCurrentEdge->myHighWayType = key + "." + value;
00612             }
00613             myCurrentEdge->myCurrentIsRoad = true;
00614         } else if (key == "lanes") {
00615             try {
00616                 myCurrentEdge->myNoLanes = TplConvert<char>::_2int(value.c_str());
00617             } catch (NumberFormatException&) {
00618                 // might be a list of values
00619                 StringTokenizer st(value, ";", true);
00620                 std::vector<std::string> list = st.getVector();
00621                 if (list.size() >= 2) {
00622                     int minLanes = std::numeric_limits<int>::max();
00623                     try {
00624                         for (std::vector<std::string>::iterator i = list.begin(); i != list.end(); ++i) {
00625                             int numLanes = TplConvert<char>::_2int(StringUtils::prune(*i).c_str());
00626                             minLanes = MIN2(minLanes, numLanes);
00627                         }
00628                         myCurrentEdge->myNoLanes = minLanes;
00629                         WRITE_WARNING("Using minimum lane number from list (" + value + ") for edge '" + myCurrentEdge->id + "'.");
00630                     } catch (NumberFormatException&) {
00631                         WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in edge '" + myCurrentEdge->id + "'.");
00632                     }
00633                 }
00634             }
00635         } else if (key == "maxspeed") {
00636             if (mySpeedMap.find(value) != mySpeedMap.end()) {
00637                 myCurrentEdge->myMaxSpeed = mySpeedMap[value];
00638             } else {
00639                 SUMOReal conversion = 1; // OSM default is km/h
00640                 if (StringUtils::to_lower_case(value).find("km/h") != std::string::npos) {
00641                     value = StringUtils::prune(value.substr(0, value.find_first_not_of("0123456789")));
00642                 } else if (StringUtils::to_lower_case(value).find("mph") != std::string::npos) {
00643                     value = StringUtils::prune(value.substr(0, value.find_first_not_of("0123456789")));
00644                     conversion = 1.609344; // kilometers per mile
00645                 }
00646                 try {
00647                     myCurrentEdge->myMaxSpeed = TplConvert<char>::_2SUMOReal(value.c_str()) * conversion;
00648                 } catch (NumberFormatException&) {
00649                     WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in edge '" + myCurrentEdge->id + "'.");
00650                 }
00651             }
00652         } else if (key == "junction") {
00653             if ((value == "roundabout") && (myCurrentEdge->myIsOneWay == "")) {
00654                 myCurrentEdge->myIsOneWay = "yes";
00655             }
00656         } else if (key == "oneway") {
00657             myCurrentEdge->myIsOneWay = value;
00658         } else if (key == "name") {
00659             myCurrentEdge->streetName = value;
00660         }
00661     }
00662 }
00663 
00664 
00665 void
00666 NIImporter_OpenStreetMap::EdgesHandler::myEndElement(int element) {
00667     myParentElements.pop_back();
00668     if (element == SUMO_TAG_WAY) {
00669         if (myCurrentEdge != 0 && myCurrentEdge->myCurrentIsRoad) {
00670             myEdgeMap[myCurrentEdge->id] = myCurrentEdge;
00671         } else {
00672             delete myCurrentEdge;
00673         }
00674         myCurrentEdge = 0;
00675     }
00676 }
00677 
00678 
00679 
00680 
00681 /****************************************************************************/
00682 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Defines