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