osgEarth 2.1.1
|
00001 /* -*-c++-*- */ 00002 /* osgEarth - Dynamic map generation toolkit for OpenSceneGraph 00003 * Copyright 2008-2010 Pelican Mapping 00004 * http://osgearth.org 00005 * 00006 * osgEarth is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU Lesser General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public License 00017 * along with this program. If not, see <http://www.gnu.org/licenses/> 00018 */ 00019 00020 #include <osgEarth/GeoMath> 00021 00022 using namespace osgEarth; 00023 00024 double 00025 GeoMath::distance(double lat1Rad, double lon1Rad, double lat2Rad, double lon2Rad, double radius) 00026 { 00027 double dLat = (lat2Rad-lat1Rad); 00028 double dLon = (lon2Rad-lon1Rad); 00029 double a = sin(dLat/2.0) * sin(dLat/2.0) + 00030 cos(lat1Rad) * cos(lat2Rad) * 00031 sin(dLon/2.0) * sin(dLon/2.0); 00032 double c = 2.0 * atan2(sqrt(a), sqrt(1.0-a)); 00033 double d = radius * c; 00034 return d; 00035 } 00036 00037 double 00038 GeoMath::distance(const std::vector< osg::Vec3d > &points, double radius) 00039 { 00040 double length = 0; 00041 00042 if (points.size() > 1) 00043 { 00044 for (unsigned int i = 0; i < points.size()-1; ++i) 00045 { 00046 const osg::Vec3d& current = points[i]; 00047 const osg::Vec3d& next = points[i+1]; 00048 length += GeoMath::distance(osg::DegreesToRadians(current.y()), osg::DegreesToRadians(current.x()), 00049 osg::DegreesToRadians(next.y()), osg::DegreesToRadians(next.x()), radius); 00050 } 00051 } 00052 return length; 00053 } 00054 00055 double 00056 GeoMath::distance(const osg::Vec3d& p1, const osg::Vec3d& p2, const SpatialReference* srs ) 00057 { 00058 if ( srs == 0L || srs->isProjected() ) 00059 { 00060 return (p2-p1).length(); 00061 } 00062 else 00063 { 00064 return distance( 00065 osg::DegreesToRadians( p1.y() ), osg::DegreesToRadians( p1.x() ), 00066 osg::DegreesToRadians( p2.y() ), osg::DegreesToRadians( p2.x() ), 00067 srs->getEllipsoid()->getRadiusEquator() ); 00068 } 00069 } 00070 00071 double 00072 GeoMath::bearing(double lat1Rad, double lon1Rad, 00073 double lat2Rad, double lon2Rad) 00074 { 00075 double dLon = (lon2Rad-lon1Rad); 00076 double y = sin(dLon) * cos(lat2Rad); 00077 double x = cos(lat1Rad)*sin(lat2Rad) - sin(lat1Rad)*cos(lat2Rad)*cos(dLon); 00078 double brng = atan2(y, x); 00079 return brng; 00080 } 00081 00082 void 00083 GeoMath::midpoint(double lat1Rad, double lon1Rad, 00084 double lat2Rad, double lon2Rad, 00085 double &out_latRad, double &out_lonRad) 00086 { 00087 double dLon = (lon2Rad-lon1Rad); 00088 00089 double cosLat1 = cos(lat1Rad); 00090 double cosLat2 = cos(lat2Rad); 00091 double sinLat1 = sin(lat1Rad); 00092 double sinLat2 = sin(lat2Rad); 00093 00094 00095 double Bx = cosLat2 * cos(dLon); 00096 double By = cosLat2 * sin(dLon); 00097 out_latRad = atan2(sinLat1+sinLat2, 00098 sqrt( (cosLat1+Bx)*(cosLat1+Bx) + By*By) ); 00099 out_lonRad = lon1Rad + atan2(By, cosLat1 + Bx); 00100 } 00101 00102 void 00103 GeoMath::destination(double lat1Rad, double lon1Rad, 00104 double bearingRad, double distance, 00105 double &out_latRad, double &out_lonRad, 00106 double radius) 00107 { 00108 double dR = distance / radius; 00109 out_latRad = asin( sin(lat1Rad)*cos(dR) + 00110 cos(lat1Rad)*sin(dR)*cos(bearingRad) ); 00111 out_lonRad = lon1Rad + atan2(sin(bearingRad)*sin(dR)*cos(lat1Rad), 00112 cos(dR)-sin(lat1Rad)*sin(out_latRad)); 00113 } 00114 00115 00116 double 00117 GeoMath::rhumbDistance(double lat1Rad, double lon1Rad, 00118 double lat2Rad, double lon2Rad, 00119 double radius) 00120 { 00121 double dLat = (lat2Rad - lat1Rad); 00122 double dLon = osg::absolute(lon2Rad - lon1Rad); 00123 00124 double dPhi = log(tan(lat2Rad/2.0+osg::PI/4.0)/tan(lat1Rad/2.0+osg::PI/4.0)); 00125 double q = (!osg::isNaN(dLat/dPhi)) ? dLat/dPhi : cos(lat1Rad); // E-W line gives dPhi=0 00126 // if dLon over 180° take shorter rhumb across 180° meridian: 00127 if (dLon > osg::PI) dLon = 2.0*osg::PI - dLon; 00128 double dist = sqrt(dLat*dLat + q*q*dLon*dLon) * radius; 00129 return dist; 00130 } 00131 00132 double 00133 GeoMath::rhumbDistance(const std::vector< osg::Vec3d > &points, double radius) 00134 { 00135 double length = 0; 00136 if (points.size() > 1) 00137 { 00138 for (unsigned int i = 0; i < points.size()-1; ++i) 00139 { 00140 const osg::Vec3d& current = points[i]; 00141 const osg::Vec3d& next = points[i+1]; 00142 length += GeoMath::rhumbDistance(osg::DegreesToRadians(current.y()), osg::DegreesToRadians(current.x()), 00143 osg::DegreesToRadians(next.y()), osg::DegreesToRadians(next.x()), radius); 00144 } 00145 } 00146 return length; 00147 } 00148 00149 double 00150 GeoMath::rhumbBearing(double lat1Rad, double lon1Rad, 00151 double lat2Rad, double lon2Rad) 00152 { 00153 double dLon = lon2Rad - lon1Rad; 00154 00155 double dPhi = log(tan(lat2Rad/2.0+osg::PI/4.0)/tan(lat1Rad/2.0+osg::PI/4.0)); 00156 if (osg::absolute(dLon) > osg::PI) dLon = dLon > 0.0 ? -(2.0*osg::PI-dLon) : (2.0*osg::PI+dLon); 00157 double brng = atan2(dLon, dPhi); 00158 return fmod(brng + 2.0 * osg::PI, 2.0 * osg::PI); 00159 00160 } 00161 00162 void 00163 GeoMath::rhumbDestination(double lat1Rad, double lon1Rad, 00164 double bearing, double distance, 00165 double &out_latRad, double &out_lonRad, 00166 double radius) 00167 { 00168 double R = radius; 00169 double d = distance / R; 00170 00171 double lat2Rad = lat1Rad + d*cos(bearing); 00172 double dLat = lat2Rad-lat1Rad; 00173 double dPhi = log(tan(lat2Rad/2.0+osg::PI/4.0)/tan(lat1Rad/2.0+osg::PI/4.0)); 00174 double q = (!osg::isNaN(dLat/dPhi)) ? dLat/dPhi : cos(lat1Rad); // E-W line gives dPhi=0 00175 double dLon = d*sin(bearing)/q; 00176 // check for some daft bugger going past the pole 00177 if (osg::absolute(lat2Rad) > osg::PI/2.0) lat2Rad = lat2Rad > 0.0 ? osg::PI-lat2Rad : -(osg::PI-lat2Rad); 00178 //double lon2Rad = (lon1Rad+dLon+3.0*Math.PI)%(2.0*osg::PI) - osg::PI; 00179 double lon2Rad = fmod((lon1Rad+dLon+3.0*osg::PI),(2.0*osg::PI)) - osg::PI; 00180 00181 out_latRad = lat2Rad; 00182 out_lonRad = lon2Rad; 00183 } 00184