|
SUMO - Simulation of Urban MObility
|
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