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 XXX preferred 00206 nbe->setPermissions(parseVehicleClasses(lane->allow, lane->disallow), fromLaneIndex); 00207 // width, offset 00208 nbe->setWidth(fromLaneIndex, lane->width); 00209 nbe->setOffset(fromLaneIndex, lane->offset); 00210 nbe->setSpeed(fromLaneIndex, lane->maxSpeed); 00211 } 00212 nbe->declareConnectionsAsLoaded(); 00213 } 00214 // insert loaded prohibitions 00215 for (std::vector<Prohibition>::const_iterator it = myProhibitions.begin(); it != myProhibitions.end(); it++) { 00216 NBEdge* prohibitedFrom = myEdges[it->prohibitedFrom]->builtEdge; 00217 if (prohibitedFrom == 0) { 00218 WRITE_ERROR("Edge '" + it->prohibitedFrom + "' in prohibition was not built"); 00219 } else { 00220 NBNode* n = prohibitedFrom->getToNode(); 00221 n->addSortedLinkFoes( 00222 NBConnection(myEdges[it->prohibitorFrom]->builtEdge, myEdges[it->prohibitorTo]->builtEdge), 00223 NBConnection(prohibitedFrom, myEdges[it->prohibitedTo]->builtEdge)); 00224 } 00225 } 00226 00227 // final warning 00228 if (mySuspectKeepShape) { 00229 WRITE_WARNING("The input network may have been built using option 'xml.keep-shape'.\n... Accuracy of junction positions cannot be guaranteed."); 00230 } 00231 00232 } 00233 00234 00235 00236 void 00237 NIImporter_SUMO::myStartElement(int element, 00238 const SUMOSAXAttributes& attrs) { 00239 /* our goal is to reproduce the input net faithfully 00240 * there are different types of objects in the netfile: 00241 * 1) those which must be loaded into NBNetBuilder-Containers for processing 00242 * 2) those which can be ignored because they are recomputed based on group 1 00243 * 3) those which are of no concern to NBNetBuilder but should be exposed to 00244 * NETEDIT. We will probably have to patch NBNetBuilder to contain them 00245 * and hand them over to NETEDIT 00246 * alternative idea: those shouldn't really be contained within the 00247 * network but rather in separate files. teach NETEDIT how to open those 00248 * (POI?) 00249 * 4) those which are of concern neither to NBNetBuilder nor NETEDIT and 00250 * must be copied over - need to patch NBNetBuilder for this. 00251 * copy unknown by default 00252 */ 00253 switch (element) { 00254 case SUMO_TAG_EDGE: 00255 addEdge(attrs); 00256 break; 00257 case SUMO_TAG_LANE: 00258 addLane(attrs); 00259 break; 00260 case SUMO_TAG_JUNCTION: 00261 addJunction(attrs); 00262 break; 00263 case SUMO_TAG_SUCC: 00264 addSuccEdge(attrs); 00265 break; 00266 case SUMO_TAG_SUCCLANE: 00267 addSuccLane(attrs); 00268 break; 00269 case SUMO_TAG_CONNECTION: 00270 addConnection(attrs); 00271 break; 00272 case SUMO_TAG_TLLOGIC__DEPRECATED: 00273 case SUMO_TAG_TLLOGIC: 00274 myCurrentTL = initTrafficLightLogic(attrs, myCurrentTL); 00275 break; 00276 case SUMO_TAG_PHASE: 00277 addPhase(attrs, myCurrentTL); 00278 break; 00279 case SUMO_TAG_LOCATION: 00280 myLocation = loadLocation(attrs); 00281 break; 00282 case SUMO_TAG_PROHIBITION: 00283 addProhibition(attrs); 00284 break; 00285 default: 00286 break; 00287 } 00288 } 00289 00290 00291 void 00292 NIImporter_SUMO::myCharacters(int element, 00293 const std::string& chars) { 00294 UNUSED_PARAMETER(element); 00295 UNUSED_PARAMETER(chars); 00296 } 00297 00298 00299 void 00300 NIImporter_SUMO::myEndElement(int element) { 00301 switch (element) { 00302 case SUMO_TAG_EDGE: 00303 if (myEdges.find(myCurrentEdge->id) != myEdges.end()) { 00304 WRITE_ERROR("Edge '" + myCurrentEdge->id + "' occured at least twice in the input."); 00305 } else { 00306 myEdges[myCurrentEdge->id] = myCurrentEdge; 00307 } 00308 myCurrentEdge = 0; 00309 break; 00310 case SUMO_TAG_LANE: 00311 if (myCurrentEdge != 0) { 00312 myCurrentEdge->maxSpeed = MAX2(myCurrentEdge->maxSpeed, myCurrentLane->maxSpeed); 00313 myCurrentEdge->lanes.push_back(myCurrentLane); 00314 } 00315 myCurrentLane = 0; 00316 break; 00317 case SUMO_TAG_TLLOGIC__DEPRECATED: 00318 case SUMO_TAG_TLLOGIC: 00319 if (!myCurrentTL) { 00320 WRITE_ERROR("Unmatched closing tag for tl-logic."); 00321 } else { 00322 if (!myTLLCont.insert(myCurrentTL)) { 00323 WRITE_WARNING("Could not add program '" + myCurrentTL->getProgramID() + 00324 "' for traffic light '" + myCurrentTL->getID() + "'"); 00325 delete myCurrentTL; 00326 } 00327 myCurrentTL = 0; 00328 } 00329 break; 00330 default: 00331 break; 00332 } 00333 } 00334 00335 00336 void 00337 NIImporter_SUMO::addEdge(const SUMOSAXAttributes& attrs) { 00338 // get the id, report an error if not given or empty... 00339 bool ok = true; 00340 std::string id = attrs.getStringReporting(SUMO_ATTR_ID, 0, ok); 00341 if (!ok) { 00342 return; 00343 } 00344 myCurrentEdge = new EdgeAttrs(); 00345 myCurrentEdge->builtEdge = 0; 00346 myCurrentEdge->id = id; 00347 // get the function 00348 myCurrentEdge->func = attrs.getOptStringReporting(SUMO_ATTR_FUNCTION, id.c_str(), ok, "normal"); 00349 if (myCurrentEdge->func == toString(EDGEFUNC_INTERNAL)) { 00350 return; // skip internal edges 00351 } 00352 // get the type 00353 myCurrentEdge->type = attrs.getOptStringReporting(SUMO_ATTR_TYPE, id.c_str(), ok, ""); 00354 // get the origin and the destination node 00355 myCurrentEdge->fromNode = attrs.getOptStringReporting(SUMO_ATTR_FROM, id.c_str(), ok, ""); 00356 myCurrentEdge->toNode = attrs.getOptStringReporting(SUMO_ATTR_TO, id.c_str(), ok, ""); 00357 myCurrentEdge->priority = attrs.getOptIntReporting(SUMO_ATTR_PRIORITY, id.c_str(), ok, -1); 00358 myCurrentEdge->type = attrs.getOptStringReporting(SUMO_ATTR_TYPE, id.c_str(), ok, ""); 00359 myCurrentEdge->shape = GeomConvHelper::parseShapeReporting( 00360 attrs.getOptStringReporting(SUMO_ATTR_SHAPE, id.c_str(), ok, ""), 00361 attrs.getObjectType(), id.c_str(), ok, true); 00362 NILoader::transformCoordinates(myCurrentEdge->shape, true, myLocation); 00363 myCurrentEdge->length = attrs.getOptSUMORealReporting(SUMO_ATTR_LENGTH, id.c_str(), ok, NBEdge::UNSPECIFIED_LOADED_LENGTH); 00364 myCurrentEdge->maxSpeed = 0; 00365 myCurrentEdge->streetName = attrs.getOptStringReporting(SUMO_ATTR_NAME, id.c_str(), ok, ""); 00366 00367 std::string lsfS = toString(LANESPREAD_RIGHT); 00368 if (attrs.hasAttribute(SUMO_ATTR_SPREADFUNC__DEPRECATED)) { 00369 lsfS = attrs.getStringReporting(SUMO_ATTR_SPREADFUNC__DEPRECATED, id.c_str(), ok); 00370 if (!myHaveWarnedAboutDeprecatedSpreadType) { 00371 WRITE_WARNING("'" + toString(SUMO_ATTR_SPREADFUNC__DEPRECATED) + "' is deprecated; please use '" + toString(SUMO_ATTR_SPREADTYPE) + "'."); 00372 myHaveWarnedAboutDeprecatedSpreadType = true; 00373 } 00374 } else { 00375 lsfS = attrs.getOptStringReporting(SUMO_ATTR_SPREADTYPE, id.c_str(), ok, lsfS); 00376 } 00377 if (SUMOXMLDefinitions::LaneSpreadFunctions.hasString(lsfS)) { 00378 myCurrentEdge->lsf = SUMOXMLDefinitions::LaneSpreadFunctions.get(lsfS); 00379 } else { 00380 WRITE_ERROR("Unknown spreadType '" + lsfS + "' for edge '" + id + "'."); 00381 } 00382 } 00383 00384 00385 void 00386 NIImporter_SUMO::addLane(const SUMOSAXAttributes& attrs) { 00387 bool ok = true; 00388 std::string id = attrs.getStringReporting(SUMO_ATTR_ID, 0, ok); 00389 if (!ok) { 00390 return; 00391 } 00392 if (!myCurrentEdge) { 00393 WRITE_ERROR("Found lane '" + id + "' not within edge element"); 00394 return; 00395 } 00396 myCurrentLane = new LaneAttrs; 00397 if (myCurrentEdge->func == toString(EDGEFUNC_INTERNAL)) { 00398 return; // skip internal lanes 00399 } 00400 if (attrs.hasAttribute(SUMO_ATTR_MAXSPEED__DEPRECATED)) { 00401 myCurrentLane->maxSpeed = attrs.getSUMORealReporting(SUMO_ATTR_MAXSPEED__DEPRECATED, id.c_str(), ok); 00402 if (!myHaveWarnedAboutDeprecatedMaxSpeed) { 00403 myHaveWarnedAboutDeprecatedMaxSpeed = true; 00404 WRITE_WARNING("'" + toString(SUMO_ATTR_MAXSPEED__DEPRECATED) + "' is deprecated, please use '" + toString(SUMO_ATTR_SPEED) + "' instead."); 00405 } 00406 } else { 00407 myCurrentLane->maxSpeed = attrs.getSUMORealReporting(SUMO_ATTR_SPEED, id.c_str(), ok); 00408 } 00409 myCurrentLane->allow = attrs.getOptStringReporting(SUMO_ATTR_ALLOW, id.c_str(), ok, ""); 00410 myCurrentLane->disallow = attrs.getOptStringReporting(SUMO_ATTR_DISALLOW, id.c_str(), ok, ""); 00411 myCurrentLane->width = attrs.getOptSUMORealReporting(SUMO_ATTR_WIDTH, id.c_str(), ok, (SUMOReal) NBEdge::UNSPECIFIED_WIDTH); 00412 myCurrentLane->offset = attrs.getOptSUMORealReporting(SUMO_ATTR_ENDOFFSET, id.c_str(), ok, (SUMOReal) NBEdge::UNSPECIFIED_OFFSET); 00413 myCurrentLane->shape = GeomConvHelper::parseShapeReporting( 00414 attrs.getStringReporting(SUMO_ATTR_SHAPE, id.c_str(), ok), 00415 attrs.getObjectType(), id.c_str(), ok, false); 00416 // lane coordinates are derived (via lane spread) do not include them in convex boundary 00417 NILoader::transformCoordinates(myCurrentLane->shape, false, myLocation); 00418 } 00419 00420 00421 void 00422 NIImporter_SUMO::addJunction(const SUMOSAXAttributes& attrs) { 00423 // get the id, report an error if not given or empty... 00424 bool ok = true; 00425 std::string id = attrs.getStringReporting(SUMO_ATTR_ID, 0, ok); 00426 if (!ok) { 00427 return; 00428 } 00429 if (id[0] == ':') { // internal node 00430 return; 00431 } 00432 SumoXMLNodeType type = NODETYPE_UNKNOWN; 00433 std::string typeS = attrs.getStringReporting(SUMO_ATTR_TYPE, id.c_str(), ok); 00434 if (SUMOXMLDefinitions::NodeTypes.hasString(typeS)) { 00435 type = SUMOXMLDefinitions::NodeTypes.get(typeS); 00436 if (type == NODETYPE_DEAD_END_DEPRECATED) { // patch legacy type 00437 type = NODETYPE_DEAD_END; 00438 } 00439 } else { 00440 WRITE_WARNING("Unknown node type '" + typeS + "' for junction '" + id + "'."); 00441 } 00442 Position pos = readPosition(attrs, id, ok); 00443 NILoader::transformCoordinates(pos, true, myLocation); 00444 // the network may have been built with the option "plain.keep-edge-shape" this 00445 // makes accurate reconstruction of legacy networks impossible. We ought to warn about this 00446 std::string shapeS = attrs.getStringReporting(SUMO_ATTR_SHAPE, id.c_str(), ok, false); 00447 if (shapeS != "") { 00448 PositionVector shape = GeomConvHelper::parseShapeReporting( 00449 shapeS, attrs.getObjectType(), id.c_str(), ok, false); 00450 shape.push_back_noDoublePos(shape[0]); // need closed shape 00451 if (!shape.around(pos) && shape.distance(pos) > 1) { // MAGIC_THRESHOLD 00452 // WRITE_WARNING("Junction '" + id + "': distance between pos and shape is " + toString(shape.distance(pos))); 00453 mySuspectKeepShape = true; 00454 } 00455 } 00456 NBNode* node = new NBNode(id, pos, type); 00457 if (!myNodeCont.insert(node)) { 00458 WRITE_ERROR("Problems on adding junction '" + id + "'."); 00459 delete node; 00460 return; 00461 } 00462 } 00463 00464 00465 void 00466 NIImporter_SUMO::addSuccEdge(const SUMOSAXAttributes& attrs) { 00467 bool ok = true; 00468 std::string edge_id = attrs.getStringReporting(SUMO_ATTR_EDGE, 0, ok); 00469 myCurrentEdge = 0; 00470 if (myEdges.count(edge_id) == 0) { 00471 WRITE_ERROR("Unknown edge '" + edge_id + "' given in succedge."); 00472 return; 00473 } 00474 myCurrentEdge = myEdges[edge_id]; 00475 std::string lane_id = attrs.getStringReporting(SUMO_ATTR_LANE, 0, ok); 00476 myCurrentLane = getLaneAttrsFromID(myCurrentEdge, lane_id); 00477 } 00478 00479 00480 void 00481 NIImporter_SUMO::addSuccLane(const SUMOSAXAttributes& attrs) { 00482 if (myCurrentLane == 0) { 00483 WRITE_ERROR("Found succlane outside succ element"); 00484 return; 00485 } 00486 bool ok = true; 00487 Connection conn; 00488 std::string laneID = attrs.getStringReporting(SUMO_ATTR_LANE, 0, ok); 00489 if (laneID == "SUMO_NO_DESTINATION") { // legacy check 00490 // deprecated 00491 return; 00492 } 00493 interpretLaneID(laneID, conn.toEdgeID, conn.toLaneIdx); 00494 conn.tlID = attrs.getOptStringReporting(SUMO_ATTR_TLID, 0, ok, ""); 00495 conn.mayDefinitelyPass = false; // (attrs.getStringReporting(SUMO_ATTR_STATE, 0, ok, "") == "M"); 00496 if (conn.tlID != "") { 00497 conn.tlLinkNo = attrs.hasAttribute(SUMO_ATTR_TLLINKINDEX) 00498 ? attrs.getIntReporting(SUMO_ATTR_TLLINKINDEX, 0, ok) 00499 : attrs.getIntReporting(SUMO_ATTR_TLLINKNO__DEPRECATED, 0, ok); 00500 } 00501 myCurrentLane->connections.push_back(conn); 00502 } 00503 00504 00505 void 00506 NIImporter_SUMO::addConnection(const SUMOSAXAttributes& attrs) { 00507 bool ok = true; 00508 std::string fromID = attrs.getStringReporting(SUMO_ATTR_FROM, 0, ok); 00509 if (myEdges.count(fromID) == 0) { 00510 WRITE_ERROR("Unknown edge '" + fromID + "' given in connection."); 00511 return; 00512 } 00513 EdgeAttrs* from = myEdges[fromID]; 00514 Connection conn; 00515 conn.toEdgeID = attrs.getStringReporting(SUMO_ATTR_TO, 0, ok); 00516 unsigned int fromLaneIdx = attrs.getIntReporting(SUMO_ATTR_FROM_LANE, 0, ok); 00517 conn.toLaneIdx = attrs.getIntReporting(SUMO_ATTR_TO_LANE, 0, ok); 00518 conn.tlID = attrs.getOptStringReporting(SUMO_ATTR_TLID, 0, ok, ""); 00519 conn.mayDefinitelyPass = false; // (attrs.getStringReporting(SUMO_ATTR_STATE, 0, ok, "") == "M"); 00520 if (conn.tlID != "") { 00521 conn.tlLinkNo = attrs.getIntReporting(SUMO_ATTR_TLLINKINDEX, 0, ok); 00522 } 00523 00524 if (from->lanes.size() <= (size_t) fromLaneIdx) { 00525 WRITE_ERROR("Invalid lane index '" + toString(fromLaneIdx) + "' for connection from '" + fromID + "'."); 00526 return; 00527 } 00528 from->lanes[fromLaneIdx]->connections.push_back(conn); 00529 } 00530 00531 00532 void 00533 NIImporter_SUMO::addProhibition(const SUMOSAXAttributes& attrs) { 00534 bool ok = true; 00535 std::string prohibitor = attrs.getOptStringReporting(SUMO_ATTR_PROHIBITOR, 0, ok, ""); 00536 std::string prohibited = attrs.getOptStringReporting(SUMO_ATTR_PROHIBITED, 0, ok, ""); 00537 if (!ok) { 00538 return; 00539 } 00540 Prohibition p; 00541 parseProhibitionConnection(prohibitor, p.prohibitorFrom, p.prohibitorTo, ok); 00542 parseProhibitionConnection(prohibited, p.prohibitedFrom, p.prohibitedTo, ok); 00543 if (!ok) { 00544 return; 00545 } 00546 myProhibitions.push_back(p); 00547 } 00548 00549 00550 NIImporter_SUMO::LaneAttrs* 00551 NIImporter_SUMO::getLaneAttrsFromID(EdgeAttrs* edge, std::string lane_id) { 00552 std::string edge_id; 00553 unsigned int index; 00554 interpretLaneID(lane_id, edge_id, index); 00555 assert(edge->id == edge_id); 00556 if (edge->lanes.size() <= (size_t) index) { 00557 WRITE_ERROR("Unknown lane '" + lane_id + "' given in succedge."); 00558 return 0; 00559 } else { 00560 return edge->lanes[index]; 00561 } 00562 } 00563 00564 00565 void 00566 NIImporter_SUMO::interpretLaneID(const std::string& lane_id, std::string& edge_id, unsigned int& index) { 00567 // assume lane_id = edge_id + '_' + index 00568 size_t sep_index = lane_id.rfind('_'); 00569 if (sep_index == std::string::npos) { 00570 WRITE_ERROR("Invalid lane id '" + lane_id + "' (missing '_')."); 00571 } 00572 edge_id = lane_id.substr(0, sep_index); 00573 std::string index_string = lane_id.substr(sep_index + 1); 00574 try { 00575 index = (unsigned int)TplConvert<char>::_2int(index_string.c_str()); 00576 } catch (NumberFormatException) { 00577 WRITE_ERROR("Invalid lane index '" + index_string + "' for lane '" + lane_id + "'."); 00578 } 00579 } 00580 00581 00582 NBLoadedSUMOTLDef* 00583 NIImporter_SUMO::initTrafficLightLogic(const SUMOSAXAttributes& attrs, NBLoadedSUMOTLDef* currentTL) { 00584 if (currentTL) { 00585 WRITE_ERROR("Definition of tl-logic '" + currentTL->getID() + "' was not finished."); 00586 return 0; 00587 } 00588 bool ok = true; 00589 std::string id = attrs.getStringReporting(SUMO_ATTR_ID, 0, ok); 00590 SUMOTime offset = TIME2STEPS(attrs.getSUMORealReporting(SUMO_ATTR_OFFSET, id.c_str(), ok)); 00591 std::string programID = attrs.getOptStringReporting(SUMO_ATTR_PROGRAMID, id.c_str(), ok, "<unknown>"); 00592 std::string type = attrs.getStringReporting(SUMO_ATTR_TYPE, 0, ok); 00593 if (type != toString(TLTYPE_STATIC)) { 00594 WRITE_WARNING("Traffic light '" + id + "' has unsupported type '" + type + "' and will be converted to '" + 00595 toString(TLTYPE_STATIC) + "'"); 00596 } 00597 if (ok) { 00598 return new NBLoadedSUMOTLDef(id, programID, offset); 00599 } else { 00600 return 0; 00601 } 00602 } 00603 00604 00605 void 00606 NIImporter_SUMO::addPhase(const SUMOSAXAttributes& attrs, NBLoadedSUMOTLDef* currentTL) { 00607 if (!currentTL) { 00608 WRITE_ERROR("found phase without tl-logic"); 00609 return; 00610 } 00611 const std::string& id = currentTL->getID(); 00612 bool ok = true; 00613 std::string state = attrs.getStringReporting(SUMO_ATTR_STATE, id.c_str(), ok); 00614 SUMOTime duration = TIME2STEPS(attrs.getSUMORealReporting(SUMO_ATTR_DURATION, id.c_str(), ok)); 00615 if (duration < 0) { 00616 WRITE_ERROR("Phase duration for tl-logic '" + id + "/" + currentTL->getProgramID() + "' must be positive."); 00617 return; 00618 } 00619 // if the traffic light is an actuated traffic light, try to get 00620 // the minimum and maximum durations 00621 //SUMOTime minDuration = attrs.getOptSUMOTimeReporting(SUMO_ATTR_MINDURATION, id.c_str(), ok, -1); 00622 //SUMOTime maxDuration = attrs.getOptSUMOTimeReporting(SUMO_ATTR_MAXDURATION, id.c_str(), ok, -1); 00623 if (ok) { 00624 currentTL->addPhase(duration, state); 00625 } 00626 } 00627 00628 00629 PositionVector 00630 NIImporter_SUMO::reconstructEdgeShape(const EdgeAttrs* edge, const Position& from, const Position& to) { 00631 const PositionVector& firstLane = edge->lanes[0]->shape; 00632 PositionVector result; 00633 result.push_back(from); 00634 00635 // reverse logic of NBEdge::computeLaneShape 00636 // !!! this will only work for old-style constant width lanes 00637 const size_t noLanes = edge->lanes.size(); 00638 for (unsigned int i = 1; i < firstLane.size() - 1; i++) { 00639 Position from = firstLane[i - 1]; 00640 Position me = firstLane[i]; 00641 Position to = firstLane[i + 1]; 00642 std::pair<SUMOReal, SUMOReal> offsets = NBEdge::laneOffset( 00643 from, me, SUMO_const_laneWidthAndOffset, (unsigned int)noLanes - 1, 00644 noLanes, edge->lsf, false); 00645 std::pair<SUMOReal, SUMOReal> offsets2 = NBEdge::laneOffset( 00646 me, to, SUMO_const_laneWidthAndOffset, (unsigned int)noLanes - 1, 00647 noLanes, edge->lsf, false); 00648 00649 Line l1( 00650 Position(from.x() + offsets.first, from.y() + offsets.second), 00651 Position(me.x() + offsets.first, me.y() + offsets.second)); 00652 l1.extrapolateBy(100); 00653 Line l2( 00654 Position(me.x() + offsets2.first, me.y() + offsets2.second), 00655 Position(to.x() + offsets2.first, to.y() + offsets2.second)); 00656 l2.extrapolateBy(100); 00657 if (l1.intersects(l2)) { 00658 result.push_back(l1.intersectsAt(l2)); 00659 } else { 00660 WRITE_WARNING("Could not reconstruct shape for edge '" + edge->id + "'."); 00661 } 00662 } 00663 00664 result.push_back(to); 00665 return result; 00666 } 00667 00668 00669 GeoConvHelper* 00670 NIImporter_SUMO::loadLocation(const SUMOSAXAttributes& attrs) { 00671 // @todo refactor parsing of location since its duplicated in NLHandler and PCNetProjectionLoader 00672 bool ok = true; 00673 GeoConvHelper* result = 0; 00674 PositionVector s = GeomConvHelper::parseShapeReporting( 00675 attrs.getStringReporting(SUMO_ATTR_NET_OFFSET, 0, ok), 00676 attrs.getObjectType(), 0, ok, false); 00677 Boundary convBoundary = GeomConvHelper::parseBoundaryReporting( 00678 attrs.getStringReporting(SUMO_ATTR_CONV_BOUNDARY, 0, ok), 00679 attrs.getObjectType(), 0, ok); 00680 Boundary origBoundary = GeomConvHelper::parseBoundaryReporting( 00681 attrs.getStringReporting(SUMO_ATTR_ORIG_BOUNDARY, 0, ok), 00682 attrs.getObjectType(), 0, ok); 00683 std::string proj = attrs.getStringReporting(SUMO_ATTR_ORIG_PROJ, 0, ok); 00684 if (ok) { 00685 Position networkOffset = s[0]; 00686 result = new GeoConvHelper(proj, networkOffset, origBoundary, convBoundary); 00687 GeoConvHelper::setLoaded(*result); 00688 } 00689 return result; 00690 } 00691 00692 00693 Position 00694 NIImporter_SUMO::readPosition(const SUMOSAXAttributes& attrs, const std::string& id, bool& ok) { 00695 SUMOReal x = attrs.getSUMORealReporting(SUMO_ATTR_X, id.c_str(), ok); 00696 SUMOReal y = attrs.getSUMORealReporting(SUMO_ATTR_Y, id.c_str(), ok); 00697 SUMOReal z = 0; 00698 if (attrs.hasAttribute(SUMO_ATTR_Z)) { 00699 z = attrs.getSUMORealReporting(SUMO_ATTR_Z, id.c_str(), ok); 00700 } 00701 return Position(x, y, z); 00702 } 00703 00704 00705 void 00706 NIImporter_SUMO::parseProhibitionConnection(const std::string& attr, std::string& from, std::string& to, bool& ok) { 00707 // split from/to 00708 size_t div = attr.find("->"); 00709 if (div == std::string::npos) { 00710 WRITE_ERROR("Missing connection divider in prohibition attribute '" + attr + "'"); 00711 ok = false; 00712 } 00713 from = attr.substr(0, div); 00714 to = attr.substr(div + 2); 00715 // check whether the definition includes a lane information and discard it 00716 if (from.find('_') != std::string::npos) { 00717 from = from.substr(0, from.find('_')); 00718 } 00719 if (to.find('_') != std::string::npos) { 00720 to = to.substr(0, to.find('_')); 00721 } 00722 // check whether the edges are known 00723 if (myEdges.count(from) == 0) { 00724 WRITE_ERROR("Unknown edge prohibition '" + from + "'"); 00725 ok = false; 00726 } 00727 if (myEdges.count(to) == 0) { 00728 WRITE_ERROR("Unknown edge prohibition '" + to + "'"); 00729 ok = false; 00730 } 00731 } 00732 /****************************************************************************/