SUMO - Simulation of Urban MObility

GeoConvHelper.cpp

Go to the documentation of this file.
00001 /****************************************************************************/
00007 // static methods for processing the coordinates conversion for the current net
00008 /****************************************************************************/
00009 // SUMO, Simulation of Urban MObility; see http://sumo.sourceforge.net/
00010 // Copyright (C) 2001-2011 DLR (http://www.dlr.de/) and contributors
00011 /****************************************************************************/
00012 //
00013 //   This program is free software; you can redistribute it and/or modify
00014 //   it under the terms of the GNU General Public License as published by
00015 //   the Free Software Foundation; either version 2 of the License, or
00016 //   (at your option) any later version.
00017 //
00018 /****************************************************************************/
00019 
00020 
00021 // ===========================================================================
00022 // included modules
00023 // ===========================================================================
00024 #ifdef _MSC_VER
00025 #include <windows_config.h>
00026 #else
00027 #include <config.h>
00028 #endif
00029 
00030 #include <map>
00031 #include <cmath>
00032 #include <cassert>
00033 #include <utils/common/MsgHandler.h>
00034 #include <utils/common/ToString.h>
00035 #include <utils/geom/GeomHelper.h>
00036 #include <utils/options/OptionsCont.h>
00037 #include "GeoConvHelper.h"
00038 
00039 #ifdef CHECK_MEMORY_LEAKS
00040 #include <foreign/nvwa/debug_new.h>
00041 #endif // CHECK_MEMORY_LEAKS
00042 
00043 
00044 // ===========================================================================
00045 // static member variables
00046 // ===========================================================================
00047 GeoConvHelper GeoConvHelper::myDefault("!", Position(), Boundary(), Boundary());
00048 GeoConvHelper GeoConvHelper::myLoaded("!", Position(), Boundary(), Boundary());
00049 GeoConvHelper GeoConvHelper::myOutput("!", Position(), Boundary(), Boundary());
00050 int GeoConvHelper::myNumLoaded = 0;
00051 
00052 // ===========================================================================
00053 // method definitions
00054 // ===========================================================================
00055 GeoConvHelper::GeoConvHelper(const std::string& proj, const Position& offset,
00056                              const Boundary& orig, const Boundary& conv, int shift, bool inverse, bool baseFound):
00057     myProjString(proj),
00058 #ifdef HAVE_PROJ
00059     myProjection(0),
00060 #endif
00061     myOffset(offset),
00062     myProjectionMethod(NONE),
00063     myOrigBoundary(orig),
00064     myConvBoundary(conv),
00065     myGeoScale(pow(10, (double)-shift)),
00066     myUseInverseProjection(inverse),
00067     myBaseFound(baseFound),
00068     myBaseX(0),
00069     myBaseY(0) {
00070     if (proj == "!") {
00071         myProjectionMethod = NONE;
00072     } else if (proj == "-") {
00073         myProjectionMethod = SIMPLE;
00074     } else if (proj == "UTM") {
00075         myProjectionMethod = UTM;
00076     } else if (proj == "DHDN") {
00077         myProjectionMethod = DHDN;
00078 #ifdef HAVE_PROJ
00079     } else {
00080         myProjectionMethod = PROJ;
00081         myProjection = pj_init_plus(proj.c_str());
00082         if (myProjection == 0) {
00083             // !!! check pj_errno
00084             throw ProcessError("Could not build projection!");
00085         }
00086 #endif
00087     }
00088 }
00089 
00090 
00091 GeoConvHelper::~GeoConvHelper() {
00092 #ifdef HAVE_PROJ
00093     if (myProjection != 0) {
00094         pj_free(myProjection);
00095     }
00096 #endif
00097 }
00098 
00099 
00100 GeoConvHelper&
00101 GeoConvHelper::operator=(const GeoConvHelper& orig) {
00102     myProjString = orig.myProjString;
00103     myOffset = orig.myOffset;
00104     myProjectionMethod = orig.myProjectionMethod;
00105     myOrigBoundary = orig.myOrigBoundary;
00106     myConvBoundary = orig.myConvBoundary;
00107     myGeoScale = orig.myGeoScale;
00108     myUseInverseProjection = orig.myUseInverseProjection;
00109     myBaseFound = orig.myBaseFound;
00110     myBaseX = orig.myBaseX;
00111     myBaseY = orig.myBaseY;
00112 #ifdef HAVE_PROJ
00113     if (myProjection != 0) {
00114         pj_free(myProjection);
00115     }
00116     myProjection = (orig.myProjectionMethod == PROJ ? pj_init_plus(orig.myProjString.c_str()) : 0);
00117 #endif
00118     return *this;
00119 }
00120 
00121 
00122 bool
00123 GeoConvHelper::init(OptionsCont& oc) {
00124     std::string proj = "!"; // the default
00125     int shift = oc.getInt("proj.scale");
00126     Position offset = Position(oc.getFloat("offset.x"), oc.getFloat("offset.y"));
00127     bool inverse = oc.getBool("proj.inverse");
00128     bool baseFound = !oc.exists("offset.disable-normalization") ||
00129                      oc.getBool("offset.disable-normalization") ||
00130                      !oc.isDefault("offset.x") ||
00131                      !oc.isDefault("offset.y");
00132 
00133     if (oc.getBool("simple-projection")) {
00134         proj = "-";
00135     }
00136 
00137 #ifdef HAVE_PROJ
00138     if (oc.getBool("proj.inverse") && oc.getString("proj") == "!") {
00139         WRITE_ERROR("Inverse projection works only with explicit proj parameters.");
00140         return false;
00141     }
00142     unsigned numProjections = oc.getBool("simple-projection") + oc.getBool("proj.utm") + oc.getBool("proj.dhdn") + (oc.getString("proj").length() > 1);
00143     if (numProjections > 1) {
00144         WRITE_ERROR("The projection method needs to be uniquely defined.");
00145         return false;
00146     }
00147 
00148     if (oc.getBool("proj.utm")) {
00149         proj = "UTM";
00150     } else if (oc.getBool("proj.dhdn")) {
00151         proj = "DHDN";
00152     } else {
00153         proj = oc.getString("proj");
00154     }
00155 #endif
00156     myDefault = GeoConvHelper(proj, offset, Boundary(), Boundary(), shift, inverse, baseFound);
00157     return true;
00158 }
00159 
00160 
00161 void
00162 GeoConvHelper::init(const std::string& proj,
00163                     const Position& offset,
00164                     const Boundary& orig,
00165                     const Boundary& conv) {
00166     myDefault = GeoConvHelper(proj, offset, orig, conv);
00167 }
00168 
00169 
00170 #ifdef HAVE_PROJ
00171 void
00172 GeoConvHelper::initProjection(double x, double y) {
00173     assert(myProjection == 0); // do not reinitialize
00174 
00175     if (myProjectionMethod == UTM) {
00176         int zone = (int)(x + 180) / 6 + 1;
00177         myProjString = "+proj=utm +zone=" + toString(zone) +
00178                        " +ellps=WGS84 +datum=WGS84 +units=m +no_defs";
00179         myProjection = pj_init_plus(myProjString.c_str());
00181     }
00182     if (myProjectionMethod == DHDN) {
00183         int zone = (int)(x / 3);
00184         if (zone < 1 || zone > 5) {
00185             WRITE_WARNING("Attempt to initialize DHDN-projection on invalid longitude " + toString(x));
00186             return;
00187         }
00188         myProjString = "+proj=tmerc +lat_0=0 +lon_0=" + toString(3*zone) +
00189                        " +k=1 +x_0=" + toString(zone * 1000000 + 500000) +
00190                        " +y_0=0 +ellps=bessel +datum=potsdam +units=m +no_defs";
00191         myProjection = pj_init_plus(myProjString.c_str());
00193     }
00194 }
00195 #endif
00196 
00197 
00198 void
00199 GeoConvHelper::addProjectionOptions(OptionsCont& oc) {
00200     oc.addOptionSubTopic("Projection");
00201 
00202     oc.doRegister("simple-projection", new Option_Bool(false));
00203     oc.addSynonyme("simple-projection", "proj.simple", true);
00204     oc.addDescription("simple-projection", "Projection", "Uses a simple method for projection");
00205 
00206     oc.doRegister("proj.scale", new Option_Integer(0));
00207     oc.addSynonyme("proj.scale", "proj.shift", true);
00208     oc.addDescription("proj.scale", "Projection", "Number of places to shift decimal point to right in geo-coordinates");
00209 
00210 #ifdef HAVE_PROJ
00211     oc.doRegister("proj.utm", new Option_Bool(false));
00212     oc.addDescription("proj.utm", "Projection", "Determine the UTM zone (for a universal transversal mercator projection based on the WGS84 ellipsoid)");
00213 
00214     oc.doRegister("proj.dhdn", new Option_Bool(false));
00215     oc.addDescription("proj.dhdn", "Projection", "Determine the DHDN zone (for a transversal mercator projection based on the bessel ellipsoid)");
00216 
00217     oc.doRegister("proj", new Option_String("!"));
00218     oc.addDescription("proj", "Projection", "Uses STR as proj.4 definition for projection");
00219 
00220     oc.doRegister("proj.inverse", new Option_Bool(false));
00221     oc.addDescription("proj.inverse", "Projection", "Inverses projection");
00222 #endif // HAVE_PROJ
00223 }
00224 
00225 
00226 bool
00227 GeoConvHelper::usingGeoProjection() const {
00228     return myProjectionMethod != NONE;
00229 }
00230 
00231 
00232 bool
00233 GeoConvHelper::usingInverseGeoProjection() const {
00234     return myUseInverseProjection;
00235 }
00236 
00237 
00238 void
00239 GeoConvHelper::cartesian2geo(Position& cartesian) {
00240     cartesian.sub(myOffset);
00241     if (myProjectionMethod == NONE) {
00242         return;
00243     }
00244 #ifdef HAVE_PROJ
00245     projUV p;
00246     p.u = cartesian.x();
00247     p.v = cartesian.y();
00248     p = pj_inv(p, myProjection);
00250     p.u *= RAD_TO_DEG;
00251     p.v *= RAD_TO_DEG;
00252     cartesian.set((SUMOReal) p.u, (SUMOReal) p.v);
00253 #endif
00254 }
00255 
00256 
00257 bool
00258 GeoConvHelper::x2cartesian(Position& from, bool includeInBoundary) {
00259     myOrigBoundary.add(from);
00260     double x = from.x();
00261     double y = from.y();
00262     if (myProjectionMethod == NONE) {
00263         from.add(myOffset);
00264     } else if (myUseInverseProjection) {
00265         cartesian2geo(from);
00266     } else {
00267         x *= myGeoScale;
00268         y *= myGeoScale;
00269         if (x > 180.1 || x < -180.1 || y > 90.1 || y < -90.1) {
00270             return false;
00271         }
00272 #ifdef HAVE_PROJ
00273         if (myProjection==0) {
00274             initProjection(x, y);
00275         }
00276         if (myProjection!=0) {
00277             projUV p;
00278             p.u = x * DEG_TO_RAD;
00279             p.v = y * DEG_TO_RAD;
00280             p = pj_fwd(p, myProjection);
00282             x = p.u;
00283             y = p.v;
00284         }
00285 #endif
00286         if (myProjectionMethod == SIMPLE) {
00287             double ys = y;
00288             if (!myBaseFound) {
00289                 myBaseX = x;
00290                 myBaseY = y;
00291                 myBaseFound = true;
00292             }
00293             x -= myBaseX;
00294             y -= myBaseY;
00295             x *= 111320. * cos(ys*PI/180.0);
00296             y *= 111136.;
00297             from.set((SUMOReal)x, (SUMOReal)y);
00299             from.add(myOffset);
00300         }
00301     }
00302     if (myProjectionMethod != SIMPLE) {
00303         if (!myBaseFound) {
00304             if (x > 100000 || y > 100000) {
00305                 myBaseX = x;
00306                 myBaseY = y;
00307             }
00308             myBaseFound = true;
00309         }
00310         if (myBaseFound) {
00311             x -= myBaseX;
00312             y -= myBaseY;
00313         }
00314         from.set((SUMOReal)x, (SUMOReal)y);
00315         from.add(myOffset);
00316     }
00317     if (includeInBoundary) {
00318         myConvBoundary.add(from);
00319     }
00320     return true;
00321 }
00322 
00323 
00324 void
00325 GeoConvHelper::moveConvertedBy(SUMOReal x, SUMOReal y) {
00326     myOffset.add(x, y);
00327     myConvBoundary.moveby(x, y);
00328 }
00329 
00330 
00331 const Boundary&
00332 GeoConvHelper::getOrigBoundary() const {
00333     return myOrigBoundary;
00334 }
00335 
00336 
00337 const Boundary&
00338 GeoConvHelper::getConvBoundary() const {
00339     return myConvBoundary;
00340 }
00341 
00342 
00343 const Position
00344 GeoConvHelper::getOffset() const {
00345     return myOffset;
00346 }
00347 
00348 
00349 const Position
00350 GeoConvHelper::getOffsetBase() const {
00351     return Position(myOffset.x()-myBaseX, myOffset.y()-myBaseY);
00352 }
00353 
00354 
00355 const std::string&
00356 GeoConvHelper::getProjString() const {
00357     return myProjString;
00358 }
00359 
00360 
00361 const GeoConvHelper&
00362 GeoConvHelper:: getOutputInstance() {
00363     if (myNumLoaded == 0) {
00364         return myDefault;
00365     } else if (myNumLoaded > 1) {
00366         WRITE_WARNING("Multiple location elements have been loaded. Check output location for correctness");
00367     }
00368     myOutput = GeoConvHelper(
00369                    // prefer options over loaded location
00370                    myDefault.usingGeoProjection() ? myDefault.getProjString() : myLoaded.getProjString(),
00371                    // let offset and boundary lead back to the original coords of the loaded data
00372                    myDefault.getOffset() + myLoaded.getOffset(),
00373                    myLoaded.getOrigBoundary(),
00374                    // the new boundary (updated during loading)
00375                    myDefault.getConvBoundary());
00376     return myOutput;
00377 }
00378 
00379 /****************************************************************************/
00380 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Defines