X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fmath%2FSGGeodesy.cxx;h=b9974f14c66601be2063896c99d59fc8bfa5adc3;hb=dfea3623f6549c9173fed5149da41285863fc290;hp=e42ce1e3e47946cdc244276a0ea1f72b6892db57;hpb=2c07222ef6e95c95f09db7da1a014bcc8fb845a6;p=simgear.git diff --git a/simgear/math/SGGeodesy.cxx b/simgear/math/SGGeodesy.cxx index e42ce1e3..b9974f14 100644 --- a/simgear/math/SGGeodesy.cxx +++ b/simgear/math/SGGeodesy.cxx @@ -79,11 +79,30 @@ SGGeodesy::SGCartToGeod(const SGVec3& cart, SGGeod& geod) double Y = cart(1); double Z = cart(2); double XXpYY = X*X+Y*Y; + if( XXpYY + Z*Z < 25 ) { + // This function fails near the geocenter region, so catch that special case here. + // Define the innermost sphere of small radius as earth center and return the + // coordinates 0/0/-EQURAD. It may be any other place on geoide's surface, + // the Northpole, Hawaii or Wentorf. This one was easy to code ;-) + geod.setLongitudeRad( 0.0 ); + geod.setLongitudeRad( 0.0 ); + geod.setElevationM( -EQURAD ); + return; + } + double sqrtXXpYY = sqrt(XXpYY); double p = XXpYY*ra2; double q = Z*Z*(1-e2)*ra2; double r = 1/6.0*(p+q-e4); double s = e4*p*q/(4*r*r*r); +/* + s*(2+s) is negative for s = [-2..0] + slightly negative values for s due to floating point rounding errors + cause nan for sqrt(s*(2+s)) + We can probably clamp the resulting parable to positive numbers +*/ + if( s >= -2.0 && s <= 0.0 ) + s = 0.0; double t = pow(1+s+sqrt(s*(2+s)), 1/3.0); double u = r*(1+t+1/t); double v = sqrt(u*u+e4*q); @@ -521,7 +540,7 @@ SGGeodesy::courseRad(const SGGeoc& from, const SGGeoc& to) } double -SGGeodesy::distanceM(const SGGeoc& from, const SGGeoc& to) +SGGeodesy::distanceRad(const SGGeoc& from, const SGGeoc& to) { // d = 2*asin(sqrt((sin((lat1-lat2)/2))^2 + // cos(lat1)*cos(lat2)*(sin((lon1-lon2)/2))^2)) @@ -531,5 +550,12 @@ SGGeodesy::distanceM(const SGGeoc& from, const SGGeoc& to) double tmp2 = sin(0.5*(from.getLongitudeRad() - to.getLongitudeRad())); double square = tmp1*tmp1 + cosLatFrom*cosLatTo*tmp2*tmp2; double s = SGMiscd::min(sqrt(SGMiscd::max(square, 0)), 1); - return 2 * asin(s) * SG_RAD_TO_NM * SG_NM_TO_METER; + return 2 * asin(s); +} + + +double +SGGeodesy::distanceM(const SGGeoc& from, const SGGeoc& to) +{ + return distanceRad(from, to) * SG_RAD_TO_NM * SG_NM_TO_METER; }