// Projection.cpp: implementation of the Projection class. // // Developed by: Mike Childs // Started: 1/16/98 ////////////////////////////////////////////////////////////////////// #include "Projection.h" #include "DatumConvertor.h" #include "GeographicProjection.h" #include "gctpc/untfz.h" #ifndef NULL #define NULL 0 #endif ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// Projection::Projection( DATUM d, UNIT u, DATUM geoDatum, UNIT geoUnit ) : d_datum(d), d_unit(u), d_geoDatum(geoDatum), d_geoUnit(geoUnit) { // If the geographic datum is default just use the projection's datum if ( DEFAULT_DATUM == d_geoDatum ) { d_geoDatum = d_datum; } } Projection::Projection( const Projection& p ) { if ( this != &p ) { d_datum = p.d_datum; d_unit = p.d_unit; d_geoDatum = p.d_geoDatum; d_geoUnit = p.d_geoUnit; } } Projection::~Projection() { } // Operator overlays bool Projection::operator==( const Projection& p ) const { if ( getDatum() == p.getDatum() && getUnit() == p.getUnit() && getProjectionSystem() == p.getProjectionSystem() ) { return true; } else { return false; } } bool Projection::operator!=( const Projection& p ) const { return ( !operator==( p ) ); } string Projection::toString() const { // TODO: Make this better string str = "DATUM: "; str += datumToString( d_datum ); str += "\r\nUNIT: "; str += unitToString( d_unit ); str += "\r\n"; return str; } double Projection::packedDMSToDouble( double packedDMS ) { double sign = 1.0; if ( packedDMS < 0.0 ) { sign = -1.0; packedDMS = -packedDMS; } short deg = packedDMS / 1000000; packedDMS -= deg * 1000000; short min = packedDMS / 1000; packedDMS -= min * 1000; double result = deg; result += min / 60.0; result += packedDMS / 3600.0; result *= sign; return result; } string Projection::packedDMSToString( double packedDMS, bool bLat ) { char nsFlag = 'N'; char ewFlag = 'E'; if ( packedDMS < 0 ) { nsFlag = 'S'; ewFlag = 'W'; packedDMS *= -1; } short deg = packedDMS / 1000000; packedDMS -= deg * 1000000; short min = packedDMS / 1000; packedDMS -= min * 1000; double sec = packedDMS; char flag = bLat ? nsFlag : ewFlag; char strTemp[20]; sprintf( strTemp, "%d° %02d\' %05.2f\" %c", deg, min, sec, flag ); return strTemp; } string Projection::unitToString( UNIT u ) { switch ( u ) { case RADIANS: return "radians"; case US_FEET: return "feet"; case METERS: return "meters"; case ARC_SECONDS: return "arc seconds"; case ARC_DEGREES: return "arc degrees"; case INTERNATIONAL_FEET: return "international feet"; case STATE_ZONE_TABLE: return "state zone table units"; default: return "unknown units"; } } string Projection::datumToString( DATUM d ) { switch ( d ) { case ADINDAN: return "ADINDAN"; case ARC1950: return "ARC1950"; case ARC1960: return "ARC1960"; case AUSTRALIAN_GEODETIC_1966: return "AUSTRALIAN GEODETIC 1966"; case AUSTRALIAN_GEODETIC_1984: return "AUSTRALIAN GEODETIC 1984"; case CAMP_AREA_ASTRO: return "CAMP AREA ASTRO"; case CAPE: return "CAPE"; case EUROPEAN_DATUM_1950: return "EUROPEAN DATUM 1950"; case EUROPEAN_DATUM_1979: return "EUROPEAN DATUM 1979"; case GEODETIC_DATUM_1949: return "GEODETIC DATUM 1949"; case HONG_KONG_1963: return "HONG KONG 1963"; case HU_TZU_SHAN: return "HU TZU SHAN"; case INDIAN: return "INDIAN"; case NAD27: return "NAD27"; case NAD83: return "NAD83"; case OLD_HAWAIIAN_MEAN: return "OLD HAWAIIAN MEAN"; case OMAN: return "OMAN"; case ORDNANCE_SURVEY_1936: return "ORDNANCE SURVEY 1936"; case PULKOVO_1942: return "PULKOVO 1942"; case PROVISIONAL_S_AMERICAN_1956: return "PROVISIONAL SOUTH AMERICAN 1956"; case TOKYO: return "TOKYO"; case WGS_72: return "WGS72"; case WGS_84: return "WGS84"; case NO_DATUM: return "NO DATUM"; default: return "Unknown Datum"; } } // Datum conversion bool Projection::convertDatum( double& latitude, double& longitude, DATUM from, DATUM to ) const { // Convert the coordinates to degrees if they aren't there already double factor; untfz( d_geoUnit, ARC_DEGREES, &factor ); latitude *= factor; longitude *= factor; // Make sure the coordinates are in the valid range for this projection bool bResult = true; if ( bResult = checkCoordinateRange( latitude, longitude ) ) { // Convert the datum of the point if necessary if ( from != to ) { bResult = DatumConvertor::convertDatum( latitude, longitude, from, to ); } // Check the coordinate range again to make sure the datum stuff didn't // screw it up if ( bResult ) { bResult = checkCoordinateRange( latitude, longitude ); } } // Convert the point back to its original units latitude /= factor; longitude /= factor; return bResult; }