osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarth/GeoMath.cpp

Go to the documentation of this file.
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 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines