|
SUMO - Simulation of Urban MObility
|
00001 /****************************************************************************/ 00007 // Importer for networks stored in SUMO 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 <string> 00030 #include <utils/common/UtilExceptions.h> 00031 #include <utils/common/TplConvert.h> 00032 #include <utils/common/MsgHandler.h> 00033 #include <utils/common/StringTokenizer.h> 00034 #include <utils/common/FileHelpers.h> 00035 #include <utils/common/ToString.h> 00036 #include <utils/common/TplConvertSec.h> 00037 #include <utils/xml/SUMOXMLDefinitions.h> 00038 #include <utils/xml/SUMOSAXHandler.h> 00039 #include <utils/xml/XMLSubSys.h> 00040 #include <utils/geom/GeoConvHelper.h> 00041 #include <utils/geom/GeomConvHelper.h> 00042 #include <utils/options/OptionsCont.h> 00043 #include <netbuild/NBEdge.h> 00044 #include <netbuild/NBEdgeCont.h> 00045 #include <netbuild/NBNode.h> 00046 #include <netbuild/NBNodeCont.h> 00047 #include <netbuild/NBNetBuilder.h> 00048 #include "NILoader.h" 00049 #include "NIImporter_SUMO.h" 00050 00051 #ifdef CHECK_MEMORY_LEAKS 00052 #include <foreign/nvwa/debug_new.h> 00053 #endif // CHECK_MEMORY_LEAKS 00054 00055 00056 // =========================================================================== 00057 // method definitions 00058 // =========================================================================== 00059 // --------------------------------------------------------------------------- 00060 // static methods (interface in this case) 00061 // --------------------------------------------------------------------------- 00062 void 00063 NIImporter_SUMO::loadNetwork(const OptionsCont& oc, NBNetBuilder& nb) { 00064 NIImporter_SUMO importer(nb); 00065 importer._loadNetwork(oc); 00066 } 00067 00068 00069 // --------------------------------------------------------------------------- 00070 // loader methods 00071 // --------------------------------------------------------------------------- 00072 NIImporter_SUMO::NIImporter_SUMO(NBNetBuilder& nb) 00073 : SUMOSAXHandler("sumo-network"), 00074 myNetBuilder(nb), 00075 myNodeCont(nb.getNodeCont()), 00076 myTLLCont(nb.getTLLogicCont()), 00077 myCurrentEdge(0), 00078 myCurrentLane(0), 00079 myCurrentTL(0), 00080 myLocation(0), 00081 mySuspectKeepShape(false), 00082 myHaveWarnedAboutDeprecatedSpreadType(false), 00083 myHaveWarnedAboutDeprecatedMaxSpeed(false) {} 00084 00085 00086 NIImporter_SUMO::~NIImporter_SUMO() throw() { 00087 for (std::map<std::string, EdgeAttrs*>::const_iterator i=myEdges.begin(); i!=myEdges.end(); ++i) { 00088 EdgeAttrs* ed = (*i).second; 00089 for (std::vector<LaneAttrs*>::const_iterator j=ed->lanes.begin(); j!=ed->lanes.end(); ++j) { 00090 delete *j; 00091 } 00092 delete ed; 00093 } 00094 delete myLocation; 00095 } 00096 00097 00098 void 00099 NIImporter_SUMO::_loadNetwork(const OptionsCont& oc) { 00100 // check whether the option is set (properly) 00101 if (!oc.isUsableFileList("sumo-net-file")) { 00102 return; 00103 } 00104 // parse file(s) 00105 std::vector<std::string> files = oc.getStringVector("sumo-net-file"); 00106 for (std::vector<std::string>::const_iterator file=files.begin(); file!=files.end(); ++file) { 00107 if (!FileHelpers::exists(*file)) { 00108 WRITE_ERROR("Could not open sumo-net-file '" + *file + "'."); 00109 return; 00110 } 00111 setFileName(*file); 00112 PROGRESS_BEGIN_MESSAGE("Parsing sumo-net from '" + *file + "'"); 00113 XMLSubSys::runParser(*this, *file); 00114 PROGRESS_DONE_MESSAGE(); 00115 } 00116 // build edges 00117 for (std::map<std::string, EdgeAttrs*>::const_iterator i=myEdges.begin(); i!=myEdges.end(); ++i) { 00118 EdgeAttrs* ed = (*i).second; 00119 // skip internal edges 00120 if (ed->func == toString(EDGEFUNC_INTERNAL)) { 00121 continue; 00122 } 00123 // get and check the nodes 00124 NBNode* from = myNodeCont.retrieve(ed->fromNode); 00125 NBNode* to = myNodeCont.retrieve(ed->toNode); 00126 if (from==0) { 00127 WRITE_ERROR("Edge's '" + ed->id + "' from-node '" + ed->fromNode + "' is not known."); 00128 continue; 00129 } 00130 if (to==0) { 00131 WRITE_ERROR("Edge's '" + ed->id + "' to-node '" + ed->toNode + "' is not known."); 00132 continue; 00133 } 00134 // edge shape 00135 PositionVector geom; 00136 if (ed->shape.size() > 0) { 00137 geom = ed->shape; 00138 mySuspectKeepShape = false; // no problem with reconstruction if edge shape is given explicit 00139 } else { 00140 // either the edge has default shape consisting only of the two node 00141 // positions or we have a legacy network 00142 geom = reconstructEdgeShape(ed, from->getPosition(), to->getPosition()); 00143 } 00144 // build and insert the edge 00145 NBEdge* e = new NBEdge(ed->id, from, to, 00146 ed->type, ed->maxSpeed, 00147 (unsigned int) ed->lanes.size(), 00148 ed->priority, NBEdge::UNSPECIFIED_WIDTH, NBEdge::UNSPECIFIED_OFFSET, 00149 geom, ed->streetName, ed->lsf, true); // always use tryIgnoreNodePositions to keep original shape 00150 if (!myNetBuilder.getEdgeCont().insert(e)) { 00151 WRITE_ERROR("Could not insert edge '" + ed->id + "'."); 00152 delete e; 00153 continue; 00154 } 00155 ed->builtEdge = myNetBuilder.getEdgeCont().retrieve(ed->id); 00156 } 00157 // assign further lane attributes (edges are built) 00158 for (std::map<std::string, EdgeAttrs*>::const_iterator i=myEdges.begin(); i!=myEdges.end(); ++i) { 00159 EdgeAttrs* ed = (*i).second; 00160 NBEdge* nbe = ed->builtEdge; 00161 if (nbe == 0) { // inner edge or removed by explicit list, vclass, ... 00162 continue; 00163 } 00164 for (unsigned int fromLaneIndex=0; fromLaneIndex<(unsigned int) ed->lanes.size(); ++fromLaneIndex) { 00165 LaneAttrs* lane = ed->lanes[fromLaneIndex]; 00166 // connections 00167 const std::vector<Connection> &connections = lane->connections; 00168 for (std::vector<Connection>::const_iterator c_it=connections.begin(); c_it!=connections.end(); c_it++) { 00169 const Connection& c = *c_it; 00170 if (myEdges.count(c.toEdgeID) == 0) { 00171 WRITE_ERROR("Unknown edge '" + c.toEdgeID + "' given in connection."); 00172 continue; 00173 } 00174 NBEdge* toEdge = myEdges[c.toEdgeID]->builtEdge; 00175 if (toEdge==0) { // removed by explicit list, vclass, ... 00176 continue; 00177 } 00178 nbe->addLane2LaneConnection( 00179 fromLaneIndex, toEdge, c.toLaneIdx, NBEdge::L2L_VALIDATED, 00180 false, c.mayDefinitelyPass); 00181 00182 // maybe we have a tls-controlled connection 00183 if (c.tlID != "") { 00184 const std::map<std::string, NBTrafficLightDefinition*>& programs = myTLLCont.getPrograms(c.tlID); 00185 if (programs.size() > 0) { 00186 std::map<std::string, NBTrafficLightDefinition*>::const_iterator it; 00187 for (it = programs.begin(); it!= programs.end(); it++) { 00188 NBLoadedSUMOTLDef* tlDef = dynamic_cast<NBLoadedSUMOTLDef*>(it->second); 00189 if (tlDef) { 00190 tlDef->addConnection(nbe, toEdge, fromLaneIndex, c.toLaneIdx, c.tlLinkNo); 00191 } else { 00192 throw ProcessError("Corrupt traffic light definition '" 00193 + c.tlID + "' (program '" + it->first + "')"); 00194 } 00195 } 00196 } else { 00197 WRITE_ERROR("The traffic light '" + c.tlID + "' is not known."); 00198 } 00199 } 00200 } 00201 // allow/disallow 00202 SUMOVehicleClasses allowed; 00203 SUMOVehicleClasses disallowed; 00204 parseVehicleClasses(lane->allow, lane->disallow, allowed, disallowed); 00205 nbe->setVehicleClasses(allowed, disallowed, fromLaneIndex); 00206 // width, offset 00207 nbe->setWidth(fromLaneIndex, lane->width); 00208 nbe->setOffset(fromLaneIndex, lane->offset); 00209 nbe->setSpeed(fromLaneIndex, lane->maxSpeed); 00210 } 00211 nbe->declareConnectionsAsLoaded(); 00212 } 00213 // insert loaded prohibitions 00214 for (std::vector<Prohibition>::const_iterator it = myProhibitions.begin(); it != myProhibitions.end(); it++) { 00215 NBEdge* prohibitedFrom = myEdges[it->prohibitedFrom]->builtEdge; 00216 if (prohibitedFrom == 0) { 00217 WRITE_ERROR("Edge '" + it->prohibitedFrom + "' in prohibition was not built"); 00218 } else { 00219 NBNode* n = prohibitedFrom->getToNode(); 00220 n->addSortedLinkFoes( 00221 NBConnection(myEdges[it->prohibitorFrom]->builtEdge, myEdges[it->prohibitorTo]->builtEdge), 00222 NBConnection(prohibitedFrom, myEdges[it->prohibitedTo]->builtEdge)); 00223 } 00224 } 00225 00226 // final warning 00227 if (mySuspectKeepShape) { 00228 WRITE_WARNING("The input network may have been built using option 'xml.keep-shape'.\n... Accuracy of junction positions cannot be guaranteed."); 00229 } 00230 00231 } 00232 00233 00234 00235 void 00236 NIImporter_SUMO::myStartElement(int element, 00237 const SUMOSAXAttributes& attrs) throw(ProcessError) { 00238 /* our goal is to reproduce the input net faithfully 00239 * there are different types of objects in the netfile: 00240 * 1) those which must be loaded into NBNetBuilder-Containers for processing 00241 * 2) those which can be ignored because they are recomputed based on group 1 00242 * 3) those which are of no concern to NBNetBuilder but should be exposed to 00243 * NETEDIT. We will probably have to patch NBNetBuilder to contain them 00244 * and hand them over to NETEDIT 00245 * alternative idea: those shouldn't really be contained within the 00246 * network but rather in separate files. teach NETEDIT how to open those 00247 * (POI?) 00248 * 4) those which are of concern neither to NBNetBuilder nor NETEDIT and 00249 * must be copied over - need to patch NBNetBuilder for this. 00250 * copy unknown by default 00251 */ 00252 switch (element) { 00253 case SUMO_TAG_EDGE: 00254 addEdge(attrs); 00255 break; 00256 case SUMO_TAG_LANE: 00257 addLane(attrs); 00258 break; 00259 case SUMO_TAG_JUNCTION: 00260 addJunction(attrs); 00261 break; 00262 case SUMO_TAG_SUCC: 00263 addSuccEdge(attrs); 00264 break; 00265 case SUMO_TAG_SUCCLANE: 00266 addSuccLane(attrs); 00267 break; 00268 case SUMO_TAG_CONNECTION: 00269 addConnection(attrs); 00270 break; 00271 case SUMO_TAG_TLLOGIC__DEPRECATED: 00272 case SUMO_TAG_TLLOGIC: 00273 myCurrentTL = initTrafficLightLogic(attrs, myCurrentTL); 00274 break; 00275 case SUMO_TAG_PHASE: 00276 addPhase(attrs, myCurrentTL); 00277 break; 00278 case SUMO_TAG_LOCATION: 00279 setLocation(attrs); 00280 break; 00281 case SUMO_TAG_PROHIBITION: 00282 addProhibition(attrs); 00283 break; 00284 default: 00285 break; 00286 } 00287 } 00288 00289 00290 void 00291 NIImporter_SUMO::myCharacters(int element, 00292 const std::string& chars) throw(ProcessError) { 00293 UNUSED_PARAMETER(element); 00294 UNUSED_PARAMETER(chars); 00295 } 00296 00297 00298 void 00299 NIImporter_SUMO::myEndElement(int element) throw(ProcessError) { 00300 switch (element) { 00301 case SUMO_TAG_EDGE: 00302 if (myEdges.find(myCurrentEdge->id)!=myEdges.end()) { 00303 WRITE_ERROR("Edge '" + myCurrentEdge->id + "' occured at least twice in the input."); 00304 } else { 00305 myEdges[myCurrentEdge->id] = myCurrentEdge; 00306 } 00307 myCurrentEdge = 0; 00308 break; 00309 case SUMO_TAG_LANE: 00310 if (myCurrentEdge!=0) { 00311 myCurrentEdge->maxSpeed = MAX2(myCurrentEdge->maxSpeed, myCurrentLane->maxSpeed); 00312 myCurrentEdge->lanes.push_back(myCurrentLane); 00313 } 00314 myCurrentLane = 0; 00315 break; 00316 case SUMO_TAG_TLLOGIC__DEPRECATED: 00317 case SUMO_TAG_TLLOGIC: 00318 if (!myCurrentTL) { 00319 WRITE_ERROR("Unmatched closing tag for tl-logic."); 00320 } else { 00321 if (!myTLLCont.insert(myCurrentTL)) { 00322 WRITE_WARNING("Could not add program '" + myCurrentTL->getProgramID() + 00323 "' for traffic light '" + myCurrentTL->getID() + "'"); 00324 delete myCurrentTL; 00325 } 00326 myCurrentTL = 0; 00327 } 00328 break; 00329 default: 00330 break; 00331 } 00332 } 00333 00334 00335 void 00336 NIImporter_SUMO::addEdge(const SUMOSAXAttributes& attrs) { 00337 // get the id, report an error if not given or empty... 00338 bool ok = true; 00339 std::string id = attrs.getStringReporting(SUMO_ATTR_ID, 0, ok); 00340 if (!ok) { 00341 return; 00342 } 00343 myCurrentEdge = new EdgeAttrs; 00344 myCurrentEdge->builtEdge = 0; 00345 myCurrentEdge->id = id; 00346 // get the function 00347 myCurrentEdge->func = attrs.getOptStringReporting(SUMO_ATTR_FUNCTION, id.c_str(), ok, "normal"); 00348 if (myCurrentEdge->func == toString(EDGEFUNC_INTERNAL)) { 00349 return; // skip internal edges 00350 } 00351 // get the type 00352 myCurrentEdge->type = attrs.getOptStringReporting(SUMO_ATTR_TYPE, id.c_str(), ok, ""); 00353 // get the origin and the destination node 00354 myCurrentEdge->fromNode = attrs.getOptStringReporting(SUMO_ATTR_FROM, id.c_str(), ok, ""); 00355 myCurrentEdge->toNode = attrs.getOptStringReporting(SUMO_ATTR_TO, id.c_str(), ok, ""); 00356 myCurrentEdge->priority = attrs.getOptIntReporting(SUMO_ATTR_PRIORITY, id.c_str(), ok, -1); 00357 myCurrentEdge->type = attrs.getOptStringReporting(SUMO_ATTR_TYPE, id.c_str(), ok, ""); 00358 myCurrentEdge->shape = GeomConvHelper::parseShapeReporting( 00359 attrs.getOptStringReporting(SUMO_ATTR_SHAPE, id.c_str(), ok, ""), 00360 attrs.getObjectType(), id.c_str(), ok, true); 00361 NILoader::transformCoordinates(myCurrentEdge->shape, true, myLocation); 00362 myCurrentEdge->maxSpeed = 0; 00363 myCurrentEdge->streetName = attrs.getOptStringReporting(SUMO_ATTR_NAME, id.c_str(), ok, ""); 00364 00365 std::string lsfS = toString(LANESPREAD_RIGHT); 00366 if (attrs.hasAttribute(SUMO_ATTR_SPREADFUNC__DEPRECATED)) { 00367 lsfS = attrs.getStringReporting(SUMO_ATTR_SPREADFUNC__DEPRECATED, id.c_str(), ok); 00368 if (!myHaveWarnedAboutDeprecatedSpreadType) { 00369 WRITE_WARNING("'" + toString(SUMO_ATTR_SPREADFUNC__DEPRECATED) + "' is deprecated; please use '" + toString(SUMO_ATTR_SPREADTYPE) + "'."); 00370 myHaveWarnedAboutDeprecatedSpreadType = true; 00371 } 00372 } else { 00373 lsfS = attrs.getOptStringReporting(SUMO_ATTR_SPREADTYPE, id.c_str(), ok, lsfS); 00374 } 00375 if (SUMOXMLDefinitions::LaneSpreadFunctions.hasString(lsfS)) { 00376 myCurrentEdge->lsf = SUMOXMLDefinitions::LaneSpreadFunctions.get(lsfS); 00377 } else { 00378 WRITE_ERROR("Unknown spreadType '" + lsfS + "' for edge '" + id + "'."); 00379 } 00380 } 00381 00382 00383 void 00384 NIImporter_SUMO::addLane(const SUMOSAXAttributes& attrs) { 00385 bool ok = true; 00386 std::string id = attrs.getStringReporting(SUMO_ATTR_ID, 0, ok); 00387 if (!ok) { 00388 return; 00389 } 00390 if (!myCurrentEdge) { 00391 WRITE_ERROR("Found lane '" + id + "' not within edge element"); 00392 return; 00393 } 00394 myCurrentLane = new LaneAttrs; 00395 if (myCurrentEdge->func == toString(EDGEFUNC_INTERNAL)) { 00396 return; // skip internal lanes 00397 } 00398 if (attrs.hasAttribute(SUMO_ATTR_MAXSPEED__DEPRECATED)) { 00399 myCurrentLane->maxSpeed = attrs.getSUMORealReporting(SUMO_ATTR_MAXSPEED__DEPRECATED, id.c_str(), ok); 00400 if (!myHaveWarnedAboutDeprecatedMaxSpeed) { 00401 myHaveWarnedAboutDeprecatedMaxSpeed = true; 00402 WRITE_WARNING("'" + toString(SUMO_ATTR_MAXSPEED__DEPRECATED) + "' is deprecated, please use '" + toString(SUMO_ATTR_SPEED) + "' instead."); 00403 } 00404 } else { 00405 myCurrentLane->maxSpeed = attrs.getSUMORealReporting(SUMO_ATTR_SPEED, id.c_str(), ok); 00406 } 00407 myCurrentLane->allow = attrs.getOptStringReporting(SUMO_ATTR_ALLOW, id.c_str(), ok, ""); 00408 myCurrentLane->disallow = attrs.getOptStringReporting(SUMO_ATTR_DISALLOW, id.c_str(), ok, ""); 00409 myCurrentLane->width = attrs.getOptSUMORealReporting(SUMO_ATTR_WIDTH, id.c_str(), ok, (SUMOReal) NBEdge::UNSPECIFIED_WIDTH); 00410 myCurrentLane->offset = attrs.getOptSUMORealReporting(SUMO_ATTR_ENDOFFSET, id.c_str(), ok, (SUMOReal) NBEdge::UNSPECIFIED_OFFSET); 00411 myCurrentLane->shape = GeomConvHelper::parseShapeReporting( 00412 attrs.getStringReporting(SUMO_ATTR_SHAPE, id.c_str(), ok), 00413 attrs.getObjectType(), id.c_str(), ok, false); 00414 // lane coordinates are derived (via lane spread) do not include them in convex boundary 00415 NILoader::transformCoordinates(myCurrentLane->shape, false, myLocation); 00416 } 00417 00418 00419 void 00420 NIImporter_SUMO::addJunction(const SUMOSAXAttributes& attrs) { 00421 // get the id, report an error if not given or empty... 00422 bool ok = true; 00423 std::string id = attrs.getStringReporting(SUMO_ATTR_ID, 0, ok); 00424 if (!ok) { 00425 return; 00426 } 00427 if (id[0]==':') { // internal node 00428 return; 00429 } 00430 SumoXMLNodeType type = NODETYPE_UNKNOWN; 00431 std::string typeS = attrs.getStringReporting(SUMO_ATTR_TYPE, id.c_str(), ok); 00432 if (SUMOXMLDefinitions::NodeTypes.hasString(typeS)) { 00433 type = SUMOXMLDefinitions::NodeTypes.get(typeS); 00434 if (type == NODETYPE_DEAD_END_DEPRECATED) { // patch legacy type 00435 type = NODETYPE_DEAD_END; 00436 } 00437 } else { 00438 WRITE_WARNING("Unknown node type '" + typeS + "' for junction '" + id + "'."); 00439 } 00440 Position pos = readPosition(attrs, id, ok); 00441 NILoader::transformCoordinates(pos, true, myLocation); 00442 // the network may have been built with the option "plain.keep-edge-shape" this 00443 // makes accurate reconstruction of legacy networks impossible. We ought to warn about this 00444 std::string shapeS = attrs.getStringReporting(SUMO_ATTR_SHAPE, id.c_str(), ok, false); 00445 if (shapeS != "") { 00446 PositionVector shape = GeomConvHelper::parseShapeReporting( 00447 shapeS, attrs.getObjectType(), id.c_str(), ok, false); 00448 shape.push_back(shape[0]); // need closed shape 00449 if (!shape.around(pos) && shape.distance(pos) > 1) { // MAGIC_THRESHOLD 00450 // WRITE_WARNING("Junction '" + id + "': distance between pos and shape is " + toString(shape.distance(pos))); 00451 mySuspectKeepShape = true; 00452 } 00453 } 00454 NBNode* node = new NBNode(id, pos, type); 00455 if (!myNodeCont.insert(node)) { 00456 WRITE_ERROR("Problems on adding junction '" + id + "'."); 00457 delete node; 00458 return; 00459 } 00460 } 00461 00462 00463 void 00464 NIImporter_SUMO::addSuccEdge(const SUMOSAXAttributes& attrs) { 00465 bool ok = true; 00466 std::string edge_id = attrs.getStringReporting(SUMO_ATTR_EDGE, 0, ok); 00467 myCurrentEdge = 0; 00468 if (myEdges.count(edge_id) == 0) { 00469 WRITE_ERROR("Unknown edge '" + edge_id + "' given in succedge."); 00470 return; 00471 } 00472 myCurrentEdge = myEdges[edge_id]; 00473 std::string lane_id = attrs.getStringReporting(SUMO_ATTR_LANE, 0, ok); 00474 myCurrentLane = getLaneAttrsFromID(myCurrentEdge, lane_id); 00475 } 00476 00477 00478 void 00479 NIImporter_SUMO::addSuccLane(const SUMOSAXAttributes& attrs) { 00480 if (myCurrentLane==0) { 00481 WRITE_ERROR("Found succlane outside succ element"); 00482 return; 00483 } 00484 bool ok = true; 00485 Connection conn; 00486 std::string laneID = attrs.getStringReporting(SUMO_ATTR_LANE, 0, ok); 00487 if (laneID == "SUMO_NO_DESTINATION") { // legacy check 00488 // deprecated 00489 return; 00490 } 00491 interpretLaneID(laneID, conn.toEdgeID, conn.toLaneIdx); 00492 conn.tlID = attrs.getOptStringReporting(SUMO_ATTR_TLID, 0, ok, ""); 00493 conn.mayDefinitelyPass = false; // (attrs.getStringReporting(SUMO_ATTR_STATE, 0, ok, "") == "M"); 00494 if (conn.tlID != "") { 00495 conn.tlLinkNo = attrs.hasAttribute(SUMO_ATTR_TLLINKINDEX) 00496 ? attrs.getIntReporting(SUMO_ATTR_TLLINKINDEX, 0, ok) 00497 : attrs.getIntReporting(SUMO_ATTR_TLLINKNO__DEPRECATED, 0, ok); 00498 } 00499 myCurrentLane->connections.push_back(conn); 00500 } 00501 00502 00503 void 00504 NIImporter_SUMO::addConnection(const SUMOSAXAttributes& attrs) { 00505 bool ok = true; 00506 std::string fromID = attrs.getStringReporting(SUMO_ATTR_FROM, 0, ok); 00507 if (myEdges.count(fromID) == 0) { 00508 WRITE_ERROR("Unknown edge '" + fromID + "' given in connection."); 00509 return; 00510 } 00511 EdgeAttrs* from = myEdges[fromID]; 00512 Connection conn; 00513 conn.toEdgeID = attrs.getStringReporting(SUMO_ATTR_TO, 0, ok); 00514 unsigned int fromLaneIdx = attrs.getIntReporting(SUMO_ATTR_FROM_LANE, 0, ok); 00515 conn.toLaneIdx = attrs.getIntReporting(SUMO_ATTR_TO_LANE, 0, ok); 00516 conn.tlID = attrs.getOptStringReporting(SUMO_ATTR_TLID, 0, ok, ""); 00517 conn.mayDefinitelyPass = false; // (attrs.getStringReporting(SUMO_ATTR_STATE, 0, ok, "") == "M"); 00518 if (conn.tlID != "") { 00519 conn.tlLinkNo = attrs.getIntReporting(SUMO_ATTR_TLLINKINDEX, 0, ok); 00520 } 00521 00522 if (from->lanes.size()<=(size_t) fromLaneIdx) { 00523 WRITE_ERROR("Invalid lane index '" + toString(fromLaneIdx) + "' for connection from '" + fromID + "'."); 00524 return; 00525 } 00526 from->lanes[fromLaneIdx]->connections.push_back(conn); 00527 } 00528 00529 00530 void 00531 NIImporter_SUMO::addProhibition(const SUMOSAXAttributes& attrs) { 00532 bool ok = true; 00533 std::string prohibitor = attrs.getOptStringReporting(SUMO_ATTR_PROHIBITOR, 0, ok, ""); 00534 std::string prohibited = attrs.getOptStringReporting(SUMO_ATTR_PROHIBITED, 0, ok, ""); 00535 if (!ok) { 00536 return; 00537 } 00538 Prohibition p; 00539 parseProhibitionConnection(prohibitor, p.prohibitorFrom, p.prohibitorTo, ok); 00540 parseProhibitionConnection(prohibited, p.prohibitedFrom, p.prohibitedTo, ok); 00541 if (!ok) { 00542 return; 00543 } 00544 myProhibitions.push_back(p); 00545 } 00546 00547 00548 NIImporter_SUMO::LaneAttrs* 00549 NIImporter_SUMO::getLaneAttrsFromID(EdgeAttrs* edge, std::string lane_id) { 00550 std::string edge_id; 00551 unsigned int index; 00552 interpretLaneID(lane_id, edge_id, index); 00553 assert(edge->id == edge_id); 00554 if (edge->lanes.size()<=(size_t) index) { 00555 WRITE_ERROR("Unknown lane '" + lane_id + "' given in succedge."); 00556 return 0; 00557 } else { 00558 return edge->lanes[index]; 00559 } 00560 } 00561 00562 00563 void 00564 NIImporter_SUMO::interpretLaneID(const std::string& lane_id, std::string& edge_id, unsigned int& index) { 00565 // assume lane_id = edge_id + '_' + index 00566 size_t sep_index = lane_id.rfind('_'); 00567 if (sep_index == std::string::npos) { 00568 WRITE_ERROR("Invalid lane id '" + lane_id + "' (missing '_')."); 00569 } 00570 edge_id = lane_id.substr(0, sep_index); 00571 std::string index_string = lane_id.substr(sep_index + 1); 00572 try { 00573 index = (unsigned int)TplConvert<char>::_2int(index_string.c_str()); 00574 } catch (NumberFormatException) { 00575 WRITE_ERROR("Invalid lane index '" + index_string + "' for lane '" + lane_id + "'."); 00576 } 00577 } 00578 00579 00580 NBLoadedSUMOTLDef* 00581 NIImporter_SUMO::initTrafficLightLogic(const SUMOSAXAttributes& attrs, NBLoadedSUMOTLDef* currentTL) { 00582 if (currentTL) { 00583 WRITE_ERROR("Definition of tl-logic '" + currentTL->getID() + "' was not finished."); 00584 return 0; 00585 } 00586 bool ok = true; 00587 std::string id = attrs.getStringReporting(SUMO_ATTR_ID, 0, ok); 00588 SUMOTime offset = TIME2STEPS(attrs.getSUMORealReporting(SUMO_ATTR_OFFSET, id.c_str(), ok)); 00589 std::string programID = attrs.getOptStringReporting(SUMO_ATTR_PROGRAMID, id.c_str(), ok, "<unknown>"); 00590 std::string type = attrs.getStringReporting(SUMO_ATTR_TYPE, 0, ok); 00591 if (type != toString(TLTYPE_STATIC)) { 00592 WRITE_WARNING("Traffic light '" + id + "' has unsupported type '" + type + "' and will be converted to '" + 00593 toString(TLTYPE_STATIC) + "'"); 00594 } 00595 if (ok) { 00596 return new NBLoadedSUMOTLDef(id, programID, offset); 00597 } else { 00598 return 0; 00599 } 00600 } 00601 00602 00603 void 00604 NIImporter_SUMO::addPhase(const SUMOSAXAttributes& attrs, NBLoadedSUMOTLDef* currentTL) { 00605 if (!currentTL) { 00606 WRITE_ERROR("found phase without tl-logic"); 00607 return; 00608 } 00609 const std::string& id = currentTL->getID(); 00610 bool ok = true; 00611 std::string state = attrs.getStringReporting(SUMO_ATTR_STATE, id.c_str(), ok); 00612 SUMOTime duration = TIME2STEPS(attrs.getSUMORealReporting(SUMO_ATTR_DURATION, id.c_str(), ok)); 00613 if (duration < 0) { 00614 WRITE_ERROR("Phase duration for tl-logic '" + id + "/" + currentTL->getProgramID() + "' must be positive."); 00615 return; 00616 } 00617 // if the traffic light is an actuated traffic light, try to get 00618 // the minimum and maximum durations 00619 //SUMOTime minDuration = attrs.getOptSUMOTimeReporting(SUMO_ATTR_MINDURATION, id.c_str(), ok, -1); 00620 //SUMOTime maxDuration = attrs.getOptSUMOTimeReporting(SUMO_ATTR_MAXDURATION, id.c_str(), ok, -1); 00621 if (ok) { 00622 currentTL->addPhase(duration, state); 00623 } 00624 } 00625 00626 00627 PositionVector 00628 NIImporter_SUMO::reconstructEdgeShape(const EdgeAttrs* edge, const Position& from, const Position& to) { 00629 const PositionVector& firstLane = edge->lanes[0]->shape; 00630 PositionVector result; 00631 result.push_back(from); 00632 00633 // reverse logic of NBEdge::computeLaneShape 00634 // !!! this will only work for old-style constant width lanes 00635 const size_t noLanes = edge->lanes.size(); 00636 for (unsigned int i=1; i < firstLane.size() - 1; i++) { 00637 Position from = firstLane[i-1]; 00638 Position me = firstLane[i]; 00639 Position to = firstLane[i+1]; 00640 std::pair<SUMOReal, SUMOReal> offsets = NBEdge::laneOffset( 00641 from, me, SUMO_const_laneWidthAndOffset, (unsigned int)noLanes-1, 00642 noLanes, edge->lsf, false); 00643 std::pair<SUMOReal, SUMOReal> offsets2 = NBEdge::laneOffset( 00644 me, to, SUMO_const_laneWidthAndOffset, (unsigned int)noLanes-1, 00645 noLanes, edge->lsf, false); 00646 00647 Line l1( 00648 Position(from.x()+offsets.first, from.y()+offsets.second), 00649 Position(me.x()+offsets.first, me.y()+offsets.second)); 00650 l1.extrapolateBy(100); 00651 Line l2( 00652 Position(me.x()+offsets2.first, me.y()+offsets2.second), 00653 Position(to.x()+offsets2.first, to.y()+offsets2.second)); 00654 l2.extrapolateBy(100); 00655 if (l1.intersects(l2)) { 00656 result.push_back(l1.intersectsAt(l2)); 00657 } else { 00658 WRITE_WARNING("Could not reconstruct shape for edge '" + edge->id + "'."); 00659 } 00660 } 00661 00662 result.push_back(to); 00663 return result; 00664 } 00665 00666 00667 void 00668 NIImporter_SUMO::setLocation(const SUMOSAXAttributes& attrs) { 00669 // @todo refactor parsing of location since its duplicated in NLHandler and PCNetProjectionLoader 00670 bool ok = true; 00671 PositionVector s = GeomConvHelper::parseShapeReporting( 00672 attrs.getStringReporting(SUMO_ATTR_NET_OFFSET, 0, ok), 00673 attrs.getObjectType(), 0, ok, false); 00674 Boundary convBoundary = GeomConvHelper::parseBoundaryReporting( 00675 attrs.getStringReporting(SUMO_ATTR_CONV_BOUNDARY, 0, ok), 00676 attrs.getObjectType(), 0, ok); 00677 Boundary origBoundary = GeomConvHelper::parseBoundaryReporting( 00678 attrs.getStringReporting(SUMO_ATTR_ORIG_BOUNDARY, 0, ok), 00679 attrs.getObjectType(), 0, ok); 00680 std::string proj = attrs.getStringReporting(SUMO_ATTR_ORIG_PROJ, 0, ok); 00681 if (ok) { 00682 Position networkOffset = s[0]; 00683 myLocation = new GeoConvHelper(proj, networkOffset, origBoundary, convBoundary); 00684 GeoConvHelper::setLoaded(*myLocation); 00685 } 00686 } 00687 00688 00689 Position 00690 NIImporter_SUMO::readPosition(const SUMOSAXAttributes& attrs, const std::string& id, bool& ok) { 00691 SUMOReal x = attrs.getSUMORealReporting(SUMO_ATTR_X, id.c_str(), ok); 00692 SUMOReal y = attrs.getSUMORealReporting(SUMO_ATTR_Y, id.c_str(), ok); 00693 SUMOReal z = 0; 00694 if (attrs.hasAttribute(SUMO_ATTR_Z)) { 00695 z = attrs.getSUMORealReporting(SUMO_ATTR_Z, id.c_str(), ok); 00696 } 00697 return Position(x,y,z); 00698 } 00699 00700 00701 void 00702 NIImporter_SUMO::parseProhibitionConnection(const std::string& attr, std::string& from, std::string& to, bool& ok) { 00703 // split from/to 00704 size_t div = attr.find("->"); 00705 if (div==std::string::npos) { 00706 WRITE_ERROR("Missing connection divider in prohibition attribute '" + attr + "'"); 00707 ok = false; 00708 } 00709 from = attr.substr(0, div); 00710 to = attr.substr(div+2); 00711 // check whether the definition includes a lane information and discard it 00712 if (from.find('_')!=std::string::npos) { 00713 from= from.substr(0, from.find('_')); 00714 } 00715 if (to.find('_')!=std::string::npos) { 00716 to= to.substr(0, to.find('_')); 00717 } 00718 // check whether the edges are known 00719 if (myEdges.count(from) == 0) { 00720 WRITE_ERROR("Unknown edge prohibition '" + from + "'"); 00721 ok = false; 00722 } 00723 if (myEdges.count(to) == 0) { 00724 WRITE_ERROR("Unknown edge prohibition '" + to + "'"); 00725 ok = false; 00726 } 00727 } 00728 /****************************************************************************/