SUMO - Simulation of Urban MObility

NIImporter_OpenStreetMap.cpp

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