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