/*------------------------------------------------------------------------- Projection.cxx Implementation of a class for support of multiple projection systems Written by Per Liedman, started February 2000. Copyright (C) 2000 Per Liedman, liedman@home.se This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ---------------------------------------------------------------------------*/ #include #include #include #include "Projection.hxx" #include "Geodesy.hxx" #ifndef max #define max(a,b) (((a) > (b)) ? (a) : (b)) #endif static const char *names[]={"Sanson-Flamsteed", "Equidistant Cylindrical (Equatorial)", "Equidistant Cylindrical (Local)"}; Projection::Projection() { setSystem(SANSON_FLAMSTEED); } Projection::~Projection() { } void Projection::setSystem(int id) { sysid=id; switch (sysid) { case CYL_EQUIDISTANT_EQ: case CYL_EQUIDISTANT_LOCAL: systemclass=CYLINDRICAL; break; default: systemclass=PSEUDOCYLINDRICAL; break; } } const char *Projection::getSystemName(int id) { return names[id]; } void Projection::ab_lat( float lat, float lon, float lat_r, float lon_r, sgVec3 dst ) { switch (sysid) { case SANSON_FLAMSTEED: dst[2] = earth_radius_lat( lat_r ); dst[0] = dst[2] * cos(lat)*(lon-lon_r); dst[1] = dst[2] * (lat-lat_r); break; case CYL_EQUIDISTANT_EQ: dst[2] = rec; dst[0] = dst[2] * (lon-lon_r); dst[1] = dst[2] * (lat-lat_r); break; case CYL_EQUIDISTANT_LOCAL: dst[2] = earth_radius_lat(lat_r); dst[0] = dst[2] * cos(lat_r)*(lon-lon_r); dst[1] = dst[2] * (lat-lat_r); break; } } // Pick nice angles close to xaim and yaim. Prefer a pair with similar // relationships to their respective aims, to make the grid fairly square. void Projection::nice_angle_pair( float xaim, float yaim, float *pxnice, float *pynice ) { // If each spacing is an integer multiple of the previous, new lines // appear but none disappear as you zoom in. const float nice_angles[] = { 180.0f, 90.0f, 45.0f, 15.0f, 5.0f, 1.0f, .5f, .25f, 5.0f/60, 1.0f/60 }; int ix, iy; for (ix = 1; (unsigned int)ix < sizeof(nice_angles)/sizeof(nice_angles[0]) - 1; ix++) { if (nice_angles[ix] < xaim) break; } for (iy = 1; (unsigned int)iy < sizeof(nice_angles)/sizeof(nice_angles[0]) - 1; iy++) { if (nice_angles[iy] < yaim) break; } // ix and iy each index the second of two possible angles. float xbest = 0.0, ybest = 0.0; float prev_lerr = 999; for (int x = ix-1; x <= ix; x++) { for (int y = iy-1; y <= iy; y++) { float xlerr = log(nice_angles[x]) - log(xaim); float ylerr = log(nice_angles[y]) - log(yaim); float lerr = max(fabs(xlerr - ylerr), max(fabs(xlerr), fabs(ylerr))); if (lerr < prev_lerr) { prev_lerr = lerr; xbest = nice_angles[x]; ybest = nice_angles[y]; } } } *pxnice = xbest; *pynice = ybest; }