/* @file MagEllipsoid.java * * @author marco corvi * @date nov 2011 * * @brief TopoDroid World Magnetic Model * -------------------------------------------------------- * Copyright This sowftare is distributed under GPL-3.0 or later * See the file COPYING. * -------------------------------------------------------- * Implemented after GeomagneticLibrary.c by * National Geophysical Data Center * NOAA EGC/2 * 325 Broadway * Boulder, CO 80303 USA * Attn: Susan McLean * Phone: (303) 497-6478 * Email: Susan.McLean@noaa.gov */ package com.topodroid.DistoX; // MAGtype_Ellipsoid; class MagEllipsoid { double a; /*semi-major axis of the ellipsoid*/ double b; /*semi-minor axis of the ellipsoid*/ double fla; /* flattening */ double epssq; /*first eccentricity squared */ double eps; /* first eccentricity */ double re; /* mean radius of ellipsoid*/ /* Sets WGS-84 parameters Eq. 8 p. 8 */ MagEllipsoid() { a = 6378.137; /*semi-major axis of the ellipsoid [Km] */ b = 6356.7523142; /*semi-minor axis of the ellipsoid [Km] */ fla = 1 / 298.257223563; /* flattening */ eps = Math.sqrt(1 - (b * b) / (a * a)); /*first eccentricity */ epssq = (eps * eps); /*first eccentricity squared */ re = 6371.2; /* Earth's radius */ } /* This converts the Cartesian x, y, and z coordinates to Geodetic Coordinates * x is defined as the direction pointing out of the core toward the point defined by 0 degrees latitude and longitude. * y is defined as the direction from the core toward 90 degrees east longitude along the equator * z is defined as the direction from the core out the geographic north pole */ MagGeodetic cartesianToGeodetic( MagVector V ) { MagGeodetic ret = new MagGeodetic(); /* 1.0 compute semi-minor axis and set sign to that of z in order to get sign of Phi correct */ double modified_b = (V.z < 0.0)? -b : b; /* 2.0 compute intermediate values for latitude */ double r= Math.sqrt( V.x*V.x + V.y*V.y ); double e= ( modified_b*V.z - (a*a - modified_b*modified_b) ) / ( a*r ); double f= ( modified_b*V.z + (a*a - modified_b*modified_b) ) / ( a*r ); /* 3.0 find solution to: t^4 + 2*E*t^3 + 2*F*t - 1 = 0 */ double p= (4.0 / 3.0) * (e*f + 1.0); double q= 2.0 * (e*e - f*f); double d= p*p*p + q*q; double v = ( d >= 0.0 ) ? Math.pow( (Math.sqrt( d ) - q), (1.0 / 3.0) ) - Math.pow( (Math.sqrt( d ) + q), (1.0 / 3.0) ) : 2.0 * Math.sqrt( -p ) * Math.cos( Math.acos( q/(p * Math.sqrt( -p )) ) / 3.0 ); /* 4.0 improve v NOTE: not really necessary unless point is near pole */ if ( v*v < Math.abs(p) ) { v= -(v*v*v + 2.0*q) / (3.0*p); } double g = (Math.sqrt( e*e + v ) + e) / 2.0; double t = Math.sqrt( g*g + (f - v*g)/(2.0*g - e) ) - g; double rlat = Math.atan( (a*(1.0 - t*t)) / (2.0*modified_b*t) ); ret.phi = MagUtil.RAD2DEG * rlat; /* 5.0 compute height above ellipsoid */ ret.HeightAboveEllipsoid = (r - a*t) * Math.cos(rlat) + (V.z - modified_b) * Math.sin(rlat); /* 6.0 compute longitude east of Greenwich */ double zlong = Math.atan2( V.y, V.x ); if ( zlong < 0.0 ) zlong= zlong + 2 * MagUtil.M_PI; ret.lambda = MagUtil.RAD2DEG * zlong; while(ret.lambda > 180) ret.lambda-=360; return ret; } /* This converts spherical coordinates back to geodetic coordinates. It is not used in the WMM but * may be necessary for some applications, such as geomagnetic coordinates */ MagGeodetic sphericalToGeodetic( MagSpherical spherical ) { MagVector V = spherical.toCartesian( ); return cartesianToGeodetic( V ); } /** Eq. 7 p. 8 */ MagSpherical geodeticToSpherical( MagGeodetic geodetic ) { double CosLat = Math.cos( MagUtil.DEG2RAD * geodetic.phi ); double SinLat = Math.sin( MagUtil.DEG2RAD * geodetic.phi ); double rc = a / Math.sqrt(1.0 - epssq * SinLat * SinLat); double xp = (rc + geodetic.HeightAboveEllipsoid) * CosLat; double zp = (rc * (1.0 - epssq) + geodetic.HeightAboveEllipsoid) * SinLat; double r = Math.sqrt(xp * xp + zp * zp); return new MagSpherical( geodetic.lambda, // lambda: longitude MagUtil.RAD2DEG * ( Math.asin(zp / r)), // phig: geocentric latitude r ); } }