|
SUMO - Simulation of Urban MObility
|
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