SUMO - Simulation of Urban MObility
NIImporter_ArcView.cpp
Go to the documentation of this file.
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, "&", "&amp;");
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 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Defines