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