SUMO - Simulation of Urban MObility
|
00001 /****************************************************************************/ 00011 // Importer for networks stored in ArcView-shape format 00012 /****************************************************************************/ 00013 // SUMO, Simulation of Urban MObility; see http://sumo.sourceforge.net/ 00014 // Copyright (C) 2001-2012 DLR (http://www.dlr.de/) and contributors 00015 /****************************************************************************/ 00016 // 00017 // This file is part of SUMO. 00018 // SUMO is free software: you can redistribute it and/or modify 00019 // it under the terms of the GNU General Public License as published by 00020 // the Free Software Foundation, either version 3 of the License, or 00021 // (at your option) any later version. 00022 // 00023 /****************************************************************************/ 00024 00025 00026 // =========================================================================== 00027 // included modules 00028 // =========================================================================== 00029 #ifdef _MSC_VER 00030 #include <windows_config.h> 00031 #else 00032 #include <config.h> 00033 #endif 00034 00035 #include <string> 00036 #include <utils/common/MsgHandler.h> 00037 #include <utils/common/ToString.h> 00038 #include <utils/common/TplConvert.h> 00039 #include <utils/common/StringUtils.h> 00040 #include <utils/options/OptionsCont.h> 00041 #include <utils/geom/GeomHelper.h> 00042 #include <netbuild/NBNetBuilder.h> 00043 #include <netbuild/NBHelpers.h> 00044 #include <netbuild/NBEdge.h> 00045 #include <netbuild/NBEdgeCont.h> 00046 #include <netbuild/NBTypeCont.h> 00047 #include <netbuild/NBNode.h> 00048 #include <netbuild/NBNodeCont.h> 00049 #include <netimport/NINavTeqHelper.h> 00050 #include <utils/geom/GeoConvHelper.h> 00051 #include <utils/common/FileHelpers.h> 00052 #include "NILoader.h" 00053 #include "NIImporter_ArcView.h" 00054 00055 #ifdef HAVE_GDAL 00056 #include <ogrsf_frmts.h> 00057 #endif 00058 00059 #ifdef CHECK_MEMORY_LEAKS 00060 #include <foreign/nvwa/debug_new.h> 00061 #endif // CHECK_MEMORY_LEAKS 00062 00063 00064 // =========================================================================== 00065 // method definitions 00066 // =========================================================================== 00067 // --------------------------------------------------------------------------- 00068 // static methods (interface in this case) 00069 // --------------------------------------------------------------------------- 00070 void 00071 NIImporter_ArcView::loadNetwork(const OptionsCont& oc, NBNetBuilder& nb) { 00072 if (!oc.isSet("shapefile-prefix")) { 00073 return; 00074 } 00075 // check whether the correct set of entries is given 00076 // and compute both file names 00077 std::string dbf_file = oc.getString("shapefile-prefix") + ".dbf"; 00078 std::string shp_file = oc.getString("shapefile-prefix") + ".shp"; 00079 std::string shx_file = oc.getString("shapefile-prefix") + ".shx"; 00080 // check whether the files do exist 00081 if (!FileHelpers::exists(dbf_file)) { 00082 WRITE_ERROR("File not found: " + dbf_file); 00083 } 00084 if (!FileHelpers::exists(shp_file)) { 00085 WRITE_ERROR("File not found: " + shp_file); 00086 } 00087 if (!FileHelpers::exists(shx_file)) { 00088 WRITE_ERROR("File not found: " + shx_file); 00089 } 00090 if (MsgHandler::getErrorInstance()->wasInformed()) { 00091 return; 00092 } 00093 // load the arcview files 00094 NIImporter_ArcView loader(oc, 00095 nb.getNodeCont(), nb.getEdgeCont(), nb.getTypeCont(), 00096 dbf_file, shp_file, oc.getBool("speed-in-kmh")); 00097 loader.load(); 00098 } 00099 00100 00101 00102 // --------------------------------------------------------------------------- 00103 // loader methods 00104 // --------------------------------------------------------------------------- 00105 NIImporter_ArcView::NIImporter_ArcView(const OptionsCont& oc, 00106 NBNodeCont& nc, 00107 NBEdgeCont& ec, 00108 NBTypeCont& tc, 00109 const std::string& dbf_name, 00110 const std::string& shp_name, 00111 bool speedInKMH) 00112 : myOptions(oc), mySHPName(shp_name), 00113 myNameAddition(0), 00114 myNodeCont(nc), myEdgeCont(ec), myTypeCont(tc), 00115 mySpeedInKMH(speedInKMH), 00116 myRunningNodeID(0) { 00117 UNUSED_PARAMETER(dbf_name); 00118 } 00119 00120 00121 NIImporter_ArcView::~NIImporter_ArcView() {} 00122 00123 00124 void 00125 NIImporter_ArcView::load() { 00126 #ifdef HAVE_GDAL 00127 PROGRESS_BEGIN_MESSAGE("Loading data from '" + mySHPName + "'"); 00128 OGRRegisterAll(); 00129 OGRDataSource* poDS = OGRSFDriverRegistrar::Open(mySHPName.c_str(), FALSE); 00130 if (poDS == NULL) { 00131 WRITE_ERROR("Could not open shape description '" + mySHPName + "'."); 00132 return; 00133 } 00134 00135 // begin file parsing 00136 OGRLayer* poLayer = poDS->GetLayer(0); 00137 poLayer->ResetReading(); 00138 00139 // build coordinate transformation 00140 OGRSpatialReference* origTransf = poLayer->GetSpatialRef(); 00141 OGRSpatialReference destTransf; 00142 // use wgs84 as destination 00143 destTransf.SetWellKnownGeogCS("WGS84"); 00144 OGRCoordinateTransformation* poCT = OGRCreateCoordinateTransformation(origTransf, &destTransf); 00145 if (poCT == NULL) { 00146 if (myOptions.isSet("shapefile.guess-projection")) { 00147 OGRSpatialReference origTransf2; 00148 origTransf2.SetWellKnownGeogCS("WGS84"); 00149 poCT = OGRCreateCoordinateTransformation(&origTransf2, &destTransf); 00150 } 00151 if (poCT == 0) { 00152 WRITE_WARNING("Could not create geocoordinates converter; check whether proj.4 is installed."); 00153 } 00154 } 00155 00156 OGRFeature* poFeature; 00157 poLayer->ResetReading(); 00158 while ((poFeature = poLayer->GetNextFeature()) != NULL) { 00159 // read in edge attributes 00160 std::string id, name, from_node, to_node; 00161 if(!getStringEntry(poFeature, "shapefile.street-id", "LINK_ID", true, id)) { 00162 WRITE_ERROR("Needed field '" + id + "' (from node id) is missing."); 00163 } 00164 if (id == "") { 00165 WRITE_ERROR("Could not obtain edge id."); 00166 return; 00167 } 00168 00169 getStringEntry(poFeature, "shapefile.street-id", "ST_NAME", true, name); 00170 name = StringUtils::replace(name, "&", "&"); 00171 00172 if(!getStringEntry(poFeature, "shapefile.from-id", "REF_IN_ID", true, from_node)) { 00173 WRITE_ERROR("Needed field '" + from_node + "' (from node id) is missing."); 00174 } 00175 if(!getStringEntry(poFeature, "shapefile.to-id", "NREF_IN_ID", true, to_node)) { 00176 WRITE_ERROR("Needed field '" + to_node + "' (to node id) is missing."); 00177 } 00178 00179 if (from_node == "" || to_node == "") { 00180 from_node = toString(myRunningNodeID++); 00181 to_node = toString(myRunningNodeID++); 00182 } 00183 00184 std::string type; 00185 if (myOptions.isSet("shapefile.type-id") && poFeature->GetFieldIndex(myOptions.getString("shapefile.type-id").c_str())>=0) { 00186 type = poFeature->GetFieldAsString(myOptions.getString("shapefile.type-id").c_str()); 00187 } else if(poFeature->GetFieldIndex("ST_TYP_AFT")>=0) { 00188 type = poFeature->GetFieldAsString("ST_TYP_AFT"); 00189 } 00190 SUMOReal width = myTypeCont.getWidth(type); 00191 SUMOReal speed = getSpeed(*poFeature, id); 00192 unsigned int nolanes = getLaneNo(*poFeature, id, speed); 00193 int priority = getPriority(*poFeature, id); 00194 if (nolanes == 0 || speed == 0) { 00195 if (myOptions.getBool("shapefile.use-defaults-on-failure")) { 00196 nolanes = myTypeCont.getNumLanes(""); 00197 speed = myTypeCont.getSpeed(""); 00198 } else { 00199 OGRFeature::DestroyFeature(poFeature); 00200 WRITE_ERROR("The description seems to be invalid. Please recheck usage of types."); 00201 return; 00202 } 00203 } 00204 if (mySpeedInKMH) { 00205 speed = speed / (SUMOReal) 3.6; 00206 } 00207 00208 00209 // read in the geometry 00210 OGRGeometry* poGeometry = poFeature->GetGeometryRef(); 00211 OGRwkbGeometryType gtype = poGeometry->getGeometryType(); 00212 assert(gtype == wkbLineString); 00213 OGRLineString* cgeom = (OGRLineString*) poGeometry; 00214 if (poCT != 0) { 00215 // try transform to wgs84 00216 cgeom->transform(poCT); 00217 } 00218 00219 PositionVector shape; 00220 for (int j = 0; j < cgeom->getNumPoints(); j++) { 00221 Position pos((SUMOReal) cgeom->getX(j), (SUMOReal) cgeom->getY(j)); 00222 if (!NILoader::transformCoordinates(pos)) { 00223 WRITE_WARNING("Unable to project coordinates for edge '" + id + "'."); 00224 } 00225 shape.push_back_noDoublePos(pos); 00226 } 00227 00228 // build from-node 00229 NBNode* from = myNodeCont.retrieve(from_node); 00230 if (from == 0) { 00231 Position from_pos = shape[0]; 00232 from = myNodeCont.retrieve(from_pos); 00233 if (from == 0) { 00234 from = new NBNode(from_node, from_pos); 00235 if (!myNodeCont.insert(from)) { 00236 WRITE_ERROR("Node '" + from_node + "' could not be added"); 00237 delete from; 00238 continue; 00239 } 00240 } 00241 } 00242 // build to-node 00243 NBNode* to = myNodeCont.retrieve(to_node); 00244 if (to == 0) { 00245 Position to_pos = shape[-1]; 00246 to = myNodeCont.retrieve(to_pos); 00247 if (to == 0) { 00248 to = new NBNode(to_node, to_pos); 00249 if (!myNodeCont.insert(to)) { 00250 WRITE_ERROR("Node '" + to_node + "' could not be added"); 00251 delete to; 00252 continue; 00253 } 00254 } 00255 } 00256 00257 if (from == to) { 00258 WRITE_WARNING("Edge '" + id + "' connects identical nodes, skipping."); 00259 continue; 00260 } 00261 00262 // retrieve the information whether the street is bi-directional 00263 std::string dir; 00264 int index = poFeature->GetDefnRef()->GetFieldIndex("DIR_TRAVEL"); 00265 if (index >= 0 && poFeature->IsFieldSet(index)) { 00266 dir = poFeature->GetFieldAsString(index); 00267 } 00268 // add positive direction if wanted 00269 if (dir == "B" || dir == "F" || dir == "" || myOptions.getBool("shapefile.all-bidirectional")) { 00270 if (myEdgeCont.retrieve(id) == 0) { 00271 LaneSpreadFunction spread = dir == "B" || dir == "FALSE" ? LANESPREAD_RIGHT : LANESPREAD_CENTER; 00272 NBEdge* edge = new NBEdge(id, from, to, type, speed, nolanes, priority, width, -1, shape, "", spread); 00273 myEdgeCont.insert(edge); 00274 checkSpread(edge); 00275 } 00276 } 00277 // add negative direction if wanted 00278 if (dir == "B" || dir == "T" || myOptions.getBool("shapefile.all-bidirectional")) { 00279 id = "-" + id; 00280 if (myEdgeCont.retrieve(id) == 0) { 00281 LaneSpreadFunction spread = dir == "B" || dir == "FALSE" ? LANESPREAD_RIGHT : LANESPREAD_CENTER; 00282 NBEdge* edge = new NBEdge(id, to, from, type, speed, nolanes, priority, width, -1, shape.reverse(), "", spread); 00283 myEdgeCont.insert(edge); 00284 checkSpread(edge); 00285 } 00286 } 00287 // 00288 OGRFeature::DestroyFeature(poFeature); 00289 } 00290 PROGRESS_DONE_MESSAGE(); 00291 #else 00292 WRITE_ERROR("SUMO was compiled without GDAL support."); 00293 #endif 00294 } 00295 00296 #ifdef HAVE_GDAL 00297 SUMOReal 00298 NIImporter_ArcView::getSpeed(OGRFeature& poFeature, const std::string& edgeid) { 00299 if (myOptions.isSet("shapefile.type-id")) { 00300 return myTypeCont.getSpeed(poFeature.GetFieldAsString((char*)(myOptions.getString("shapefile.type-id").c_str()))); 00301 } 00302 // try to get definitions as to be found in SUMO-XML-definitions 00303 // idea by John Michael Calandrino 00304 int index = poFeature.GetDefnRef()->GetFieldIndex("speed"); 00305 if (index >= 0 && poFeature.IsFieldSet(index)) { 00306 return (SUMOReal) poFeature.GetFieldAsDouble(index); 00307 } 00308 index = poFeature.GetDefnRef()->GetFieldIndex("SPEED"); 00309 if (index >= 0 && poFeature.IsFieldSet(index)) { 00310 return (SUMOReal) poFeature.GetFieldAsDouble(index); 00311 } 00312 // try to get the NavTech-information 00313 index = poFeature.GetDefnRef()->GetFieldIndex("SPEED_CAT"); 00314 if (index >= 0 && poFeature.IsFieldSet(index)) { 00315 std::string def = poFeature.GetFieldAsString(index); 00316 return NINavTeqHelper::getSpeed(edgeid, def); 00317 } 00318 return -1; 00319 } 00320 00321 00322 unsigned int 00323 NIImporter_ArcView::getLaneNo(OGRFeature& poFeature, const std::string& edgeid, 00324 SUMOReal speed) { 00325 if (myOptions.isSet("shapefile.type-id")) { 00326 return (unsigned int) myTypeCont.getNumLanes(poFeature.GetFieldAsString((char*)(myOptions.getString("shapefile.type-id").c_str()))); 00327 } 00328 // try to get definitions as to be found in SUMO-XML-definitions 00329 // idea by John Michael Calandrino 00330 int index = poFeature.GetDefnRef()->GetFieldIndex("nolanes"); 00331 if (index >= 0 && poFeature.IsFieldSet(index)) { 00332 return (unsigned int) poFeature.GetFieldAsInteger(index); 00333 } 00334 index = poFeature.GetDefnRef()->GetFieldIndex("NOLANES"); 00335 if (index >= 0 && poFeature.IsFieldSet(index)) { 00336 return (unsigned int) poFeature.GetFieldAsInteger(index); 00337 } 00338 index = poFeature.GetDefnRef()->GetFieldIndex("rnol"); 00339 if (index >= 0 && poFeature.IsFieldSet(index)) { 00340 return (unsigned int) poFeature.GetFieldAsInteger(index); 00341 } 00342 index = poFeature.GetDefnRef()->GetFieldIndex("LANE_CAT"); 00343 if (index >= 0 && poFeature.IsFieldSet(index)) { 00344 std::string def = poFeature.GetFieldAsString(index); 00345 return NINavTeqHelper::getLaneNumber(edgeid, def, speed); 00346 } 00347 return 0; 00348 } 00349 00350 00351 int 00352 NIImporter_ArcView::getPriority(OGRFeature& poFeature, const std::string& /*edgeid*/) { 00353 if (myOptions.isSet("shapefile.type-id")) { 00354 return myTypeCont.getPriority(poFeature.GetFieldAsString((char*)(myOptions.getString("shapefile.type-id").c_str()))); 00355 } 00356 // try to get definitions as to be found in SUMO-XML-definitions 00357 // idea by John Michael Calandrino 00358 int index = poFeature.GetDefnRef()->GetFieldIndex("priority"); 00359 if (index >= 0 && poFeature.IsFieldSet(index)) { 00360 return poFeature.GetFieldAsInteger(index); 00361 } 00362 index = poFeature.GetDefnRef()->GetFieldIndex("PRIORITY"); 00363 if (index >= 0 && poFeature.IsFieldSet(index)) { 00364 return poFeature.GetFieldAsInteger(index); 00365 } 00366 // try to determine priority from NavTechs FUNC_CLASS attribute 00367 index = poFeature.GetDefnRef()->GetFieldIndex("FUNC_CLASS"); 00368 if (index >= 0 && poFeature.IsFieldSet(index)) { 00369 return poFeature.GetFieldAsInteger(index); 00370 } 00371 return 0; 00372 } 00373 00374 void 00375 NIImporter_ArcView::checkSpread(NBEdge* e) { 00376 NBEdge* ret = e->getToNode()->getConnectionTo(e->getFromNode()); 00377 if (ret != 0) { 00378 e->setLaneSpreadFunction(LANESPREAD_RIGHT); 00379 ret->setLaneSpreadFunction(LANESPREAD_RIGHT); 00380 } 00381 } 00382 00383 bool 00384 NIImporter_ArcView::getStringEntry(OGRFeature*poFeature, const std::string &optionName, const char *defaultName, bool prune, std::string &into) { 00385 std::string v(defaultName); 00386 if(myOptions.isSet(optionName)) { 00387 v = myOptions.getString(optionName); 00388 } 00389 if(poFeature->GetFieldIndex(v.c_str())<0) { 00390 if(myOptions.isSet(optionName)) { 00391 into = v; 00392 return false; 00393 } 00394 into = ""; 00395 return true; 00396 } 00397 into = poFeature->GetFieldAsString((char*)v.c_str()); 00398 if(prune) { 00399 into = StringUtils::prune(into); 00400 } 00401 return true; 00402 } 00403 00404 00405 00406 #endif 00407 00408 00409 00410 /****************************************************************************/ 00411