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.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