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.load(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::load(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<long, 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<long>::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<long, 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         if (e->myCurrentNodes.size() < 2) {
00256             WRITE_WARNING("Discarding way '" + e->id + "' because it has only " + toString(e->myCurrentNodes.size()) + " node(s)");
00257             continue;
00258         }
00259         // build nodes;
00260         //  - the from- and to-nodes must be built in any case
00261         //  - the in-between nodes are only built if more than one edge references them
00262         NBNode* currentFrom = insertNodeChecking(*e->myCurrentNodes.begin(), nc, tlsc);
00263         NBNode* last = insertNodeChecking(*(e->myCurrentNodes.end() - 1), nc, tlsc);
00264         int running = 0;
00265         std::vector<long> passed;
00266         for (std::vector<long>::iterator j = e->myCurrentNodes.begin(); j != e->myCurrentNodes.end(); ++j) {
00267             passed.push_back(*j);
00268             if (nodeUsage[*j] > 1 && j != e->myCurrentNodes.end() - 1 && j != e->myCurrentNodes.begin()) {
00269                 NBNode* currentTo = insertNodeChecking(*j, nc, tlsc);
00270                 running = insertEdge(e, running, currentFrom, currentTo, passed, nb);
00271                 currentFrom = currentTo;
00272                 passed.clear();
00273             }
00274         }
00275         if (running == 0) {
00276             running = -1;
00277         }
00278         insertEdge(e, running, currentFrom, last, passed, nb);
00279     }
00280 }
00281 
00282 
00283 NBNode*
00284 NIImporter_OpenStreetMap::insertNodeChecking(long id, NBNodeCont& nc, NBTrafficLightLogicCont& tlsc) {
00285     NBNode* from = nc.retrieve(toString(id));
00286     if (from == 0) {
00287         NIOSMNode* n = myOSMNodes.find(id)->second;
00288         Position pos(n->lon, n->lat);
00289         if (!NILoader::transformCoordinates(pos, true)) {
00290             WRITE_ERROR("Unable to project coordinates for node " + toString(id) + ".");
00291             delete from;
00292             return 0;
00293         }
00294         from = new NBNode(toString(id), pos);
00295         if (!nc.insert(from)) {
00296             WRITE_ERROR("Could not insert node '" + toString(id) + "').");
00297             delete from;
00298             return 0;
00299         }
00300         if (n->tlsControlled) {
00301             // ok, this node is a traffic light node where no other nodes
00302             //  participate
00303             NBOwnTLDef* tlDef = new NBOwnTLDef(toString(id), from);
00304             if (!tlsc.insert(tlDef)) {
00305                 // actually, nothing should fail here
00306                 delete tlDef;
00307                 throw ProcessError("Could not allocate tls '" + toString(id) + "'.");
00308             }
00309         }
00310     }
00311     return from;
00312 }
00313 
00314 
00315 int
00316 NIImporter_OpenStreetMap::insertEdge(Edge* e, int index, NBNode* from, NBNode* to,
00317                                      const std::vector<long> &passed, NBNetBuilder& nb) {
00318     NBNodeCont& nc = nb.getNodeCont();
00319     NBEdgeCont& ec = nb.getEdgeCont();
00320     NBTypeCont& tc = nb.getTypeCont();
00321     NBTrafficLightLogicCont& tlsc = nb.getTLLogicCont();
00322 
00323     // patch the id
00324     std::string id = e->id;
00325     if (index >= 0) {
00326         id = id + "#" + toString(index);
00327     } else {
00328         index = 0;
00329     }
00330     if (from == to) {
00331         // in the special case of a looped way split again using passed
00332         assert(passed.size() >= 2);
00333         std::vector<long> geom(passed);
00334         geom.pop_back(); // remove to-node
00335         NBNode* intermediate = insertNodeChecking(geom.back(), nc, tlsc);
00336         index = insertEdge(e, index, from, intermediate, geom, nb);
00337         geom.clear();
00338         return insertEdge(e, index, intermediate, to, geom, nb);
00339     }
00340     const int newIndex = index + 1;
00341 
00342     // convert the shape
00343     PositionVector shape;
00344     for (std::vector<long>::const_iterator i = passed.begin(); i != passed.end(); ++i) {
00345         NIOSMNode* n = myOSMNodes.find(*i)->second;
00346         Position pos(n->lon, n->lat);
00347         if (!NILoader::transformCoordinates(pos, true)) {
00348             throw ProcessError("Unable to project coordinates for edge " + id + ".");
00349         }
00350         shape.push_back_noDoublePos(pos);
00351     }
00352 
00353     std::string type = e->myHighWayType;
00354     if (!tc.knows(type)) {
00355         if (type.find(compoundTypeSeparator) != std::string::npos) {
00356             // this edge has a combination type which does not yet exist in the TypeContainer
00357             StringTokenizer tok = StringTokenizer(type, compoundTypeSeparator);
00358             std::set<std::string> types;
00359             while (tok.hasNext()) {
00360                 std::string t = tok.next();
00361                 if (tc.knows(t)) {
00362                     types.insert(t);
00363                 } else {
00364                     WRITE_WARNING("Discarding unknown compound \"" + t + "\" for edge " + id + " with type \"" + type + "\".");
00365                 }
00366             }
00367             switch (types.size()) {
00368                 case 0:
00369                     WRITE_WARNING("Discarding edge " + id + " with type unknown compound type \"" + type + "\".");
00370                     return newIndex;
00371                     break;
00372                 case 1: {
00373                     type = *(types.begin());
00374                     break;
00375                 }
00376                 default:
00377                     // build a new type by merging all values
00378                     int noLanes = 0;
00379                     SUMOReal maxSpeed = 0;
00380                     int prio = 0;
00381                     SUMOReal width = NBEdge::UNSPECIFIED_WIDTH;
00382                     bool defaultIsOneWay = false;
00383                     for (std::set<std::string>::iterator it = types.begin(); it != types.end(); it++) {
00384                         noLanes = MAX2(noLanes, tc.getNumLanes(*it));
00385                         maxSpeed = MAX2(maxSpeed, tc.getSpeed(*it));
00386                         prio = MAX2(prio, tc.getPriority(*it));
00387                         defaultIsOneWay |= tc.getIsOneWay(*it);
00388                     }
00389                     WRITE_MESSAGE("Adding new compound type \"" + type + "\" for edge " + id + ".");
00390                     // @todo use the propper bitsets instead of SVC_UNKNOWN (see #675)
00391                     tc.insert(type, noLanes, maxSpeed, prio, width, SVC_UNKNOWN, defaultIsOneWay);
00392             }
00393         } else {
00394             // we do not know the type -> something else, ignore
00395             //WRITE_WARNING("Discarding edge " + id + " with unknown type \"" + type + "\".");
00396             return newIndex;
00397         }
00398     }
00399 
00400     // otherwise it is not an edge and will be ignored
00401     int noLanes = tc.getNumLanes(type);
00402     SUMOReal speed = tc.getSpeed(type);
00403     bool defaultsToOneWay = tc.getIsOneWay(type);
00404     SVCPermissions permissions = tc.getPermissions(type);
00405     // check directions
00406     bool addSecond = true;
00407     if (e->myIsOneWay == "true" || e->myIsOneWay == "yes" || e->myIsOneWay == "1" || (defaultsToOneWay && e->myIsOneWay != "no" && e->myIsOneWay != "false" && e->myIsOneWay != "0")) {
00408         addSecond = false;
00409     }
00410     // if we had been able to extract the number of lanes, override the highway type default
00411     if (e->myNoLanes >= 0) {
00412         if (!addSecond) {
00413             noLanes = e->myNoLanes;
00414         } else {
00415             noLanes = e->myNoLanes / 2;
00416         }
00417     }
00418     // if we had been able to extract the maximum speed, override the type's default
00419     if (e->myMaxSpeed != MAXSPEED_UNGIVEN) {
00420         speed = (SUMOReal)(e->myMaxSpeed / 3.6);
00421     }
00422 
00423     if (noLanes != 0 && speed != 0) {
00424         if (e->myIsOneWay != "" && e->myIsOneWay != "false" && e->myIsOneWay != "no" && e->myIsOneWay != "true" && e->myIsOneWay != "yes" && e->myIsOneWay != "-1" && e->myIsOneWay != "1") {
00425             WRITE_WARNING("New value for oneway found: " + e->myIsOneWay);
00426         }
00427         LaneSpreadFunction lsf = addSecond ? LANESPREAD_RIGHT : LANESPREAD_CENTER;
00428         if (e->myIsOneWay != "-1") {
00429             NBEdge* nbe = new NBEdge(StringUtils::escapeXML(id), from, to, type, speed, noLanes, tc.getPriority(type),
00430                                      tc.getWidth(type), NBEdge::UNSPECIFIED_OFFSET, shape, StringUtils::escapeXML(e->streetName), lsf);
00431             nbe->setPermissions(permissions);
00432             if (!ec.insert(nbe)) {
00433                 delete nbe;
00434                 throw ProcessError("Could not add edge '" + id + "'.");
00435             }
00436         }
00437         if (addSecond) {
00438             if (e->myIsOneWay != "-1") {
00439                 id = "-" + id;
00440             }
00441             NBEdge* nbe = new NBEdge(StringUtils::escapeXML(id), to, from, type, speed, noLanes, tc.getPriority(type),
00442                                      tc.getWidth(type), NBEdge::UNSPECIFIED_OFFSET, shape.reverse(), StringUtils::escapeXML(e->streetName), lsf);
00443             nbe->setPermissions(permissions);
00444             if (!ec.insert(nbe)) {
00445                 delete nbe;
00446                 throw ProcessError("Could not add edge '-" + id + "'.");
00447             }
00448         }
00449     }
00450     return newIndex;
00451 }
00452 
00453 
00454 // ---------------------------------------------------------------------------
00455 // definitions of NIImporter_OpenStreetMap::NodesHandler-methods
00456 // ---------------------------------------------------------------------------
00457 NIImporter_OpenStreetMap::NodesHandler::NodesHandler(
00458         std::map<long, NIOSMNode*> &toFill,
00459         std::set<NIOSMNode*, CompareNodes> &uniqueNodes) : 
00460     SUMOSAXHandler("osm - file"), 
00461     myToFill(toFill), 
00462     myUniqueNodes(uniqueNodes),
00463     myLastNodeID(-1), 
00464     myIsInValidNodeTag(false), 
00465     myHierarchyLevel(0) {
00466 }
00467 
00468 
00469 NIImporter_OpenStreetMap::NodesHandler::~NodesHandler() {}
00470 
00471 
00472 void
00473 NIImporter_OpenStreetMap::NodesHandler::myStartElement(int element, const SUMOSAXAttributes& attrs) {
00474     ++myHierarchyLevel;
00475     if (element == SUMO_TAG_NODE) {
00476         bool ok = true;
00477         if (myHierarchyLevel != 2) {
00478             WRITE_ERROR("Node element on wrong XML hierarchy level (id='" + toString(attrs.getLongReporting(SUMO_ATTR_ID, 0, ok)) + "', level='" + toString(myHierarchyLevel) + "').");
00479             return;
00480         }
00481         long id = attrs.getLongReporting(SUMO_ATTR_ID, 0, ok);
00482         std::string action = attrs.hasAttribute("action") ? attrs.getStringSecure("action", "") : "";
00483         if (action == "delete") {
00484             return;
00485         }
00486         if (!ok) {
00487             return;
00488         }
00489         myLastNodeID = -1;
00490         if (myToFill.find(id) == myToFill.end()) {
00491             myLastNodeID = id;
00492             // assume we are loading multiple files...
00493             //  ... so we won't report duplicate nodes
00494             bool ok = true;
00495             double tlat, tlon;
00496             std::istringstream lon(attrs.getStringReporting(SUMO_ATTR_LON, toString(id).c_str(), ok));
00497             if (!ok) {
00498                 return;
00499             }
00500             lon >> tlon;
00501             if (lon.fail()) {
00502                 WRITE_ERROR("Node's '" + toString(id) + "' lon information is not numeric.");
00503                 return;
00504             }
00505             std::istringstream lat(attrs.getStringReporting(SUMO_ATTR_LAT, toString(id).c_str(), ok));
00506             if (!ok) {
00507                 return;
00508             }
00509             lat >> tlat;
00510             if (lat.fail()) {
00511                 WRITE_ERROR("Node's '" + toString(id) + "' lat information is not numeric.");
00512                 return;
00513             }
00514             NIOSMNode* toAdd = new NIOSMNode();
00515             toAdd->id = id;
00516             toAdd->tlsControlled = false;
00517             toAdd->lat = tlat;
00518             toAdd->lon = tlon;
00519             myIsInValidNodeTag = true;
00520 
00521             std::set<NIOSMNode*, CompareNodes>::iterator similarNode = myUniqueNodes.find(toAdd);
00522             if (similarNode == myUniqueNodes.end()) {
00523                 myUniqueNodes.insert(toAdd);
00524             } else {
00525                 delete toAdd;
00526                 toAdd = *similarNode; 
00527                 WRITE_MESSAGE("Found duplicate nodes. Substituting " + toString(id) + " with " + toString(toAdd->id));
00528             }
00529             myToFill[id] = toAdd;
00530         }
00531     }
00532     if (element == SUMO_TAG_TAG && myIsInValidNodeTag) {
00533         if (myHierarchyLevel != 3) {
00534             WRITE_ERROR("Tag element on wrong XML hierarchy level.");
00535             return;
00536         }
00537         bool ok = true;
00538         std::string key = attrs.getStringReporting(SUMO_ATTR_K, toString(myLastNodeID).c_str(), ok);
00539         std::string value = attrs.getOptStringReporting(SUMO_ATTR_V, toString(myLastNodeID).c_str(), ok, "");
00540         if (!ok) {
00541             return;
00542         }
00543         if (key == "highway" && value.find("traffic_signal") != std::string::npos &&
00544                 !OptionsCont::getOptions().getBool("osm.discard-tls")) {
00545             myToFill[myLastNodeID]->tlsControlled = true;
00546         }
00547     }
00548 }
00549 
00550 
00551 void
00552 NIImporter_OpenStreetMap::NodesHandler::myEndElement(int element) {
00553     if (element == SUMO_TAG_NODE && myHierarchyLevel == 2) {
00554         myLastNodeID = -1;
00555         myIsInValidNodeTag = false;
00556     }
00557     --myHierarchyLevel;
00558 }
00559 
00560 
00561 // ---------------------------------------------------------------------------
00562 // definitions of NIImporter_OpenStreetMap::EdgesHandler-methods
00563 // ---------------------------------------------------------------------------
00564 NIImporter_OpenStreetMap::EdgesHandler::EdgesHandler(
00565     const std::map<long, NIOSMNode*> &osmNodes,
00566     std::map<std::string, Edge*> &toFill)
00567     : SUMOSAXHandler("osm - file"),
00568       myOSMNodes(osmNodes), myEdgeMap(toFill) {
00569     mySpeedMap["signals"] = MAXSPEED_UNGIVEN;
00570     mySpeedMap["none"] = 300.;
00571     mySpeedMap["no"] = 300.;
00572     mySpeedMap["walk"] = 5.;
00573     mySpeedMap["DE:rural"] = 100.;
00574     mySpeedMap["DE:urban"] = 50.;
00575     mySpeedMap["DE:living_street"] = 10.;
00576 
00577 }
00578 
00579 
00580 NIImporter_OpenStreetMap::EdgesHandler::~EdgesHandler() {
00581 }
00582 
00583 
00584 void
00585 NIImporter_OpenStreetMap::EdgesHandler::myStartElement(int element,
00586         const SUMOSAXAttributes& attrs) {
00587     myParentElements.push_back(element);
00588     // parse "way" elements
00589     if (element == SUMO_TAG_WAY) {
00590         bool ok = true;
00591         std::string id = attrs.getStringReporting(SUMO_ATTR_ID, 0, ok);
00592         std::string action = attrs.hasAttribute("action") ? attrs.getStringSecure("action", "") : "";
00593         if (action == "delete") {
00594             myCurrentEdge = 0;
00595             return;
00596         }
00597         if (!ok) {
00598             myCurrentEdge = 0;
00599             return;
00600         }
00601         myCurrentEdge = new Edge();
00602         myCurrentEdge->id = id;
00603         myCurrentEdge->myNoLanes = -1;
00604         myCurrentEdge->myMaxSpeed = MAXSPEED_UNGIVEN;
00605         myCurrentEdge->myCurrentIsRoad = false;
00606     }
00607     // parse "nd" (node) elements
00608     if (element == SUMO_TAG_ND) {
00609         bool ok = true;
00610         long ref = attrs.getLongReporting(SUMO_ATTR_REF, 0, ok);
00611         if (ok) {
00612             std::map<long, NIOSMNode*>::const_iterator node = myOSMNodes.find(ref);
00613             if (node == myOSMNodes.end()) {
00614                 WRITE_WARNING("The referenced geometry information (ref='" + toString(ref) + "') is not known");
00615                 return;
00616             } else {
00617                 ref = node->second->id; // node may have been substituted
00618                 if (myCurrentEdge->myCurrentNodes.size() == 0 ||
00619                         myCurrentEdge->myCurrentNodes.back() != ref) { // avoid consecutive duplicates
00620                     myCurrentEdge->myCurrentNodes.push_back(ref); 
00621                 }
00622             }
00623         }
00624     }
00625     // parse values
00626     if (element == SUMO_TAG_TAG && myParentElements.size() > 2 && myParentElements[myParentElements.size() - 2] == SUMO_TAG_WAY) {
00627         if (myCurrentEdge == 0) {
00628             return;
00629         }
00630         bool ok = true;
00631         std::string key = attrs.getStringReporting(SUMO_ATTR_K, toString(myCurrentEdge->id).c_str(), ok);
00632         std::string value = attrs.getStringReporting(SUMO_ATTR_V, toString(myCurrentEdge->id).c_str(), ok);
00633         if (!ok) {
00634             return;
00635         }
00636         if (key == "highway" || key == "railway") {
00637             if (myCurrentEdge->myHighWayType != "") {
00638                 // osm-ways may be used by more than one mode (eg railway.tram + highway.residential. this is relevant for multimodal traffic)
00639                 // we create a new type for this kind of situation which must then be resolved in insertEdge()
00640                 myCurrentEdge->myHighWayType = myCurrentEdge->myHighWayType + compoundTypeSeparator + key + "." + value;
00641             } else {
00642                 myCurrentEdge->myHighWayType = key + "." + value;
00643             }
00644             myCurrentEdge->myCurrentIsRoad = true;
00645         } else if (key == "lanes") {
00646             try {
00647                 myCurrentEdge->myNoLanes = TplConvert<char>::_2int(value.c_str());
00648             } catch (NumberFormatException&) {
00649                 // might be a list of values
00650                 StringTokenizer st(value, ";", true);
00651                 std::vector<std::string> list = st.getVector();
00652                 if (list.size() >= 2) {
00653                     int minLanes = std::numeric_limits<int>::max();
00654                     try {
00655                         for (std::vector<std::string>::iterator i = list.begin(); i != list.end(); ++i) {
00656                             int numLanes = TplConvert<char>::_2int(StringUtils::prune(*i).c_str());
00657                             minLanes = MIN2(minLanes, numLanes);
00658                         }
00659                         myCurrentEdge->myNoLanes = minLanes;
00660                         WRITE_WARNING("Using minimum lane number from list (" + value + ") for edge '" + myCurrentEdge->id + "'.");
00661                     } catch (NumberFormatException&) {
00662                         WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in edge '" + myCurrentEdge->id + "'.");
00663                     }
00664                 }
00665             }
00666         } else if (key == "maxspeed") {
00667             if (mySpeedMap.find(value) != mySpeedMap.end()) {
00668                 myCurrentEdge->myMaxSpeed = mySpeedMap[value];
00669             } else {
00670                 SUMOReal conversion = 1; // OSM default is km/h
00671                 if (StringUtils::to_lower_case(value).find("km/h") != std::string::npos) {
00672                     value = StringUtils::prune(value.substr(0, value.find_first_not_of("0123456789")));
00673                 } else if (StringUtils::to_lower_case(value).find("mph") != std::string::npos) {
00674                     value = StringUtils::prune(value.substr(0, value.find_first_not_of("0123456789")));
00675                     conversion = 1.609344; // kilometers per mile
00676                 }
00677                 try {
00678                     myCurrentEdge->myMaxSpeed = TplConvert<char>::_2SUMOReal(value.c_str()) * conversion;
00679                 } catch (NumberFormatException&) {
00680                     WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in edge '" + myCurrentEdge->id + "'.");
00681                 }
00682             }
00683         } else if (key == "junction") {
00684             if ((value == "roundabout") && (myCurrentEdge->myIsOneWay == "")) {
00685                 myCurrentEdge->myIsOneWay = "yes";
00686             }
00687         } else if (key == "oneway") {
00688             myCurrentEdge->myIsOneWay = value;
00689         } else if (key == "name") {
00690             myCurrentEdge->streetName = value;
00691         }
00692     }
00693 }
00694 
00695 
00696 void
00697 NIImporter_OpenStreetMap::EdgesHandler::myEndElement(int element) {
00698     myParentElements.pop_back();
00699     if (element == SUMO_TAG_WAY) {
00700         if (myCurrentEdge != 0 && myCurrentEdge->myCurrentIsRoad) {
00701             myEdgeMap[myCurrentEdge->id] = myCurrentEdge;
00702         } else {
00703             delete myCurrentEdge;
00704         }
00705         myCurrentEdge = 0;
00706     }
00707 }
00708 
00709 
00710 
00711 
00712 /****************************************************************************/
00713 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Defines