SUMO - Simulation of Urban MObility

GeoConvHelper.cpp

Go to the documentation of this file.
00001 /****************************************************************************/
00009 // static methods for processing the coordinates conversion for the current net
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 
00033 #include <map>
00034 #include <cmath>
00035 #include <cassert>
00036 #include <utils/common/MsgHandler.h>
00037 #include <utils/common/ToString.h>
00038 #include <utils/geom/GeomHelper.h>
00039 #include <utils/options/OptionsCont.h>
00040 #include "GeoConvHelper.h"
00041 
00042 #ifdef CHECK_MEMORY_LEAKS
00043 #include <foreign/nvwa/debug_new.h>
00044 #endif // CHECK_MEMORY_LEAKS
00045 
00046 
00047 // ===========================================================================
00048 // static member variables
00049 // ===========================================================================
00050 GeoConvHelper GeoConvHelper::myProcessing("!", Position(), Boundary(), Boundary());
00051 GeoConvHelper GeoConvHelper::myLoaded("!", Position(), Boundary(), Boundary());
00052 GeoConvHelper GeoConvHelper::myFinal("!", Position(), Boundary(), Boundary());
00053 int GeoConvHelper::myNumLoaded = 0;
00054 
00055 // ===========================================================================
00056 // method definitions
00057 // ===========================================================================
00058 GeoConvHelper::GeoConvHelper(const std::string& proj, const Position& offset,
00059                              const Boundary& orig, const Boundary& conv, int shift, bool inverse, bool baseFound):
00060     myProjString(proj),
00061 #ifdef HAVE_PROJ
00062     myProjection(0),
00063 #endif
00064     myOffset(offset),
00065     myProjectionMethod(NONE),
00066     myOrigBoundary(orig),
00067     myConvBoundary(conv),
00068     myGeoScale(pow(10, (double) - shift)),
00069     myUseInverseProjection(inverse),
00070     myBaseFound(baseFound),
00071     myBaseX(0),
00072     myBaseY(0) {
00073     if (proj == "!") {
00074         myProjectionMethod = NONE;
00075     } else if (proj == "-") {
00076         myProjectionMethod = SIMPLE;
00077     } else if (proj == "UTM") {
00078         myProjectionMethod = UTM;
00079     } else if (proj == "DHDN") {
00080         myProjectionMethod = DHDN;
00081 #ifdef HAVE_PROJ
00082     } else {
00083         myProjectionMethod = PROJ;
00084         myProjection = pj_init_plus(proj.c_str());
00085         if (myProjection == 0) {
00086             // !!! check pj_errno
00087             throw ProcessError("Could not build projection!");
00088         }
00089 #endif
00090     }
00091 }
00092 
00093 
00094 GeoConvHelper::~GeoConvHelper() {
00095 #ifdef HAVE_PROJ
00096     if (myProjection != 0) {
00097         pj_free(myProjection);
00098     }
00099 #endif
00100 }
00101 
00102 
00103 GeoConvHelper&
00104 GeoConvHelper::operator=(const GeoConvHelper& orig) {
00105     myProjString = orig.myProjString;
00106     myOffset = orig.myOffset;
00107     myProjectionMethod = orig.myProjectionMethod;
00108     myOrigBoundary = orig.myOrigBoundary;
00109     myConvBoundary = orig.myConvBoundary;
00110     myGeoScale = orig.myGeoScale;
00111     myUseInverseProjection = orig.myUseInverseProjection;
00112     myBaseFound = orig.myBaseFound;
00113     myBaseX = orig.myBaseX;
00114     myBaseY = orig.myBaseY;
00115 #ifdef HAVE_PROJ
00116     if (myProjection != 0) {
00117         pj_free(myProjection);
00118     }
00119     myProjection = (orig.myProjectionMethod == PROJ ? pj_init_plus(orig.myProjString.c_str()) : 0);
00120 #endif
00121     return *this;
00122 }
00123 
00124 
00125 bool
00126 GeoConvHelper::init(OptionsCont& oc) {
00127     std::string proj = "!"; // the default
00128     int shift = oc.getInt("proj.scale");
00129     Position offset = Position(oc.getFloat("offset.x"), oc.getFloat("offset.y"));
00130     bool inverse = oc.exists("proj.inverse") && oc.getBool("proj.inverse");
00131     bool baseFound = !oc.exists("offset.disable-normalization") ||
00132                      oc.getBool("offset.disable-normalization") ||
00133                      !oc.isDefault("offset.x") ||
00134                      !oc.isDefault("offset.y");
00135 
00136     if (oc.getBool("simple-projection")) {
00137         proj = "-";
00138     }
00139 
00140 #ifdef HAVE_PROJ
00141     if (oc.getBool("proj.inverse") && oc.getString("proj") == "!") {
00142         WRITE_ERROR("Inverse projection works only with explicit proj parameters.");
00143         return false;
00144     }
00145     unsigned numProjections = oc.getBool("simple-projection") + oc.getBool("proj.utm") + oc.getBool("proj.dhdn") + (oc.getString("proj").length() > 1);
00146     if (numProjections > 1) {
00147         WRITE_ERROR("The projection method needs to be uniquely defined.");
00148         return false;
00149     }
00150 
00151     if (oc.getBool("proj.utm")) {
00152         proj = "UTM";
00153     } else if (oc.getBool("proj.dhdn")) {
00154         proj = "DHDN";
00155     } else {
00156         proj = oc.getString("proj");
00157     }
00158 #endif
00159     myProcessing = GeoConvHelper(proj, offset, Boundary(), Boundary(), shift, inverse, baseFound);
00160     myFinal = myProcessing;
00161     return true;
00162 }
00163 
00164 
00165 void
00166 GeoConvHelper::init(const std::string& proj,
00167                     const Position& offset,
00168                     const Boundary& orig,
00169                     const Boundary& conv) {
00170     myProcessing = GeoConvHelper(proj, offset, orig, conv);
00171     myFinal = myProcessing;
00172 }
00173 
00174 
00175 void
00176 GeoConvHelper::addProjectionOptions(OptionsCont& oc) {
00177     oc.addOptionSubTopic("Projection");
00178 
00179     oc.doRegister("simple-projection", new Option_Bool(false));
00180     oc.addSynonyme("simple-projection", "proj.simple", true);
00181     oc.addDescription("simple-projection", "Projection", "Uses a simple method for projection");
00182 
00183     oc.doRegister("proj.scale", new Option_Integer(0));
00184     oc.addSynonyme("proj.scale", "proj.shift", true);
00185     oc.addDescription("proj.scale", "Projection", "Number of places to shift decimal point to right in geo-coordinates");
00186 
00187 #ifdef HAVE_PROJ
00188     oc.doRegister("proj.utm", new Option_Bool(false));
00189     oc.addDescription("proj.utm", "Projection", "Determine the UTM zone (for a universal transversal mercator projection based on the WGS84 ellipsoid)");
00190 
00191     oc.doRegister("proj.dhdn", new Option_Bool(false));
00192     oc.addDescription("proj.dhdn", "Projection", "Determine the DHDN zone (for a transversal mercator projection based on the bessel ellipsoid)");
00193 
00194     oc.doRegister("proj", new Option_String("!"));
00195     oc.addDescription("proj", "Projection", "Uses STR as proj.4 definition for projection");
00196 
00197     oc.doRegister("proj.inverse", new Option_Bool(false));
00198     oc.addDescription("proj.inverse", "Projection", "Inverses projection");
00199 #endif // HAVE_PROJ
00200 }
00201 
00202 
00203 bool
00204 GeoConvHelper::usingGeoProjection() const {
00205     return myProjectionMethod != NONE;
00206 }
00207 
00208 
00209 bool
00210 GeoConvHelper::usingInverseGeoProjection() const {
00211     return myUseInverseProjection;
00212 }
00213 
00214 
00215 void
00216 GeoConvHelper::cartesian2geo(Position& cartesian) const {
00217     cartesian.sub(myOffset);
00218     if (myProjectionMethod == NONE) {
00219         return;
00220     }
00221 #ifdef HAVE_PROJ
00222     projUV p;
00223     p.u = cartesian.x();
00224     p.v = cartesian.y();
00225     p = pj_inv(p, myProjection);
00227     p.u *= RAD_TO_DEG;
00228     p.v *= RAD_TO_DEG;
00229     cartesian.set((SUMOReal) p.u, (SUMOReal) p.v);
00230 #endif
00231 }
00232 
00233 
00234 bool
00235 GeoConvHelper::x2cartesian(Position& from, bool includeInBoundary) {
00236     myOrigBoundary.add(from);
00237     // init projection parameter on first use
00238 #ifdef HAVE_PROJ
00239     if (myProjection == 0) {
00240         const double x = from.x() * myGeoScale;
00241         switch(myProjectionMethod) {
00242             case UTM: {
00243                 int zone = (int)(x + 180) / 6 + 1;
00244                 myProjString = "+proj=utm +zone=" + toString(zone) +
00245                     " +ellps=WGS84 +datum=WGS84 +units=m +no_defs";
00246                 myProjection = pj_init_plus(myProjString.c_str());
00248             }
00249             break;
00250             case DHDN: {
00251                 int zone = (int)(x / 3);
00252                 if (zone < 1 || zone > 5) {
00253                     WRITE_WARNING("Attempt to initialize DHDN-projection on invalid longitude " + toString(x));
00254                     return false;
00255                 }
00256                 myProjString = "+proj=tmerc +lat_0=0 +lon_0=" + toString(3 * zone) +
00257                     " +k=1 +x_0=" + toString(zone * 1000000 + 500000) +
00258                     " +y_0=0 +ellps=bessel +datum=potsdam +units=m +no_defs";
00259                 myProjection = pj_init_plus(myProjString.c_str());
00261             } 
00262             break;
00263             default:
00264             break;
00265         }
00266     }
00267 #endif
00268     // perform conversion
00269     bool ok = x2cartesian_const(from);
00270     if (ok) {
00271         if (!myBaseFound) {
00272             // avoid very large coordinates to reduce numerical errors
00273             if (myProjectionMethod == SIMPLE || from.x() > 100000 || from.y() > 100000) {
00274                 myBaseX = from.x();
00275                 myBaseY = from.y();
00276                 from.set(0,0);
00277             }
00278             myBaseFound = true;
00279         }
00280 
00281         if (includeInBoundary) {
00282             myConvBoundary.add(from);
00283         }
00284     }
00285     return ok;
00286 }
00287 
00288 
00289 bool
00290 GeoConvHelper::x2cartesian_const(Position& from) const {
00291     double x = from.x() * myGeoScale;
00292     double y = from.y() * myGeoScale;
00293     if (myProjectionMethod == NONE) {
00294         from.add(myOffset);
00295     } else if (myUseInverseProjection) {
00296         cartesian2geo(from);
00297     } else {
00298         if (x > 180.1 || x < -180.1 || y > 90.1 || y < -90.1) {
00299             return false;
00300         }
00301 #ifdef HAVE_PROJ
00302         if (myProjection != 0) {
00303             projUV p;
00304             p.u = x * DEG_TO_RAD;
00305             p.v = y * DEG_TO_RAD;
00306             p = pj_fwd(p, myProjection);
00308             x = p.u;
00309             y = p.v;
00310         }
00311 #endif
00312         if (myProjectionMethod == SIMPLE) {
00313             double ys = y;
00314             x -= myBaseX;
00315             y -= myBaseY;
00316             x *= 111320. * cos(ys * PI / 180.0);
00317             y *= 111136.;
00318             from.set((SUMOReal)x, (SUMOReal)y);
00320             from.add(myOffset);
00321         }
00322     }
00323     if (myProjectionMethod != SIMPLE) {
00324         x -= myBaseX;
00325         y -= myBaseY;
00326         from.set((SUMOReal)x, (SUMOReal)y);
00327         from.add(myOffset);
00328     }
00329     return true;
00330 }
00331 
00332 
00333 void
00334 GeoConvHelper::moveConvertedBy(SUMOReal x, SUMOReal y) {
00335     myOffset.add(x, y);
00336     myConvBoundary.moveby(x, y);
00337 }
00338 
00339 
00340 const Boundary&
00341 GeoConvHelper::getOrigBoundary() const {
00342     return myOrigBoundary;
00343 }
00344 
00345 
00346 const Boundary&
00347 GeoConvHelper::getConvBoundary() const {
00348     return myConvBoundary;
00349 }
00350 
00351 
00352 const Position
00353 GeoConvHelper::getOffset() const {
00354     return myOffset;
00355 }
00356 
00357 
00358 const Position
00359 GeoConvHelper::getOffsetBase() const {
00360     return Position(myOffset.x() - myBaseX, myOffset.y() - myBaseY);
00361 }
00362 
00363 
00364 const std::string&
00365 GeoConvHelper::getProjString() const {
00366     return myProjString;
00367 }
00368 
00369 
00370 void 
00371 GeoConvHelper::computeFinal() {
00372     if (myNumLoaded == 0) {
00373         myFinal = myProcessing;
00374     } else  {
00375         myFinal = GeoConvHelper(
00376                 // prefer options over loaded location
00377                 myProcessing.usingGeoProjection() ? myProcessing.getProjString() : myLoaded.getProjString(),
00378                 // let offset and boundary lead back to the original coords of the loaded data
00379                 myProcessing.getOffset() + myLoaded.getOffset(),
00380                 myLoaded.getOrigBoundary(),
00381                 // the new boundary (updated during loading)
00382                 myProcessing.getConvBoundary());
00383     }
00384 }
00385 
00386 
00387 void 
00388 GeoConvHelper::setLoaded(const GeoConvHelper& loaded) {
00389     myNumLoaded++;
00390     if (myNumLoaded > 1) {
00391         WRITE_WARNING("Ignoring loaded location attribute nr. " + toString(myNumLoaded) + " for tracking of original location");
00392     } else {
00393         myLoaded = loaded;
00394     }
00395 }
00396 
00397 
00398 void 
00399 GeoConvHelper::resetLoaded() {
00400     myNumLoaded = 0;
00401 }
00402 
00403 
00404 /****************************************************************************/
00405 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Defines