N-sim
Emulation and simulation of
Wireless Sensor Networks



   Home


   Project Page


   Download


   CVS



   Installation


   Configuration


   Plug-ins




 Hosted by
SourceForge.net Logo

/home/brennan/n-sim/OrbisQuartus/shared/coordinates.cpp

Go to the documentation of this file.
00001 
00014 /*
00015  * Copyright 2007. Los Alamos National Security, LLC. This material
00016  * was produced under U.S. Government contract DE-AC52-06NA25396 for
00017  * Los Alamos National Laboratory (LANL), which is operated by Los
00018  * Alamos National Security, LLC, for the Department of Energy. The
00019  * U.S. Government has rights to use, reproduce, and distribute this
00020  * software. NEITHER THE GOVERNMENT NOR LOS ALAMOS NATIONAL SECURITY,
00021  * LLC, MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY LEGAL
00022  * LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to
00023  * produce derivative works, such modified software should be clearly
00024  * marked, so as not to confuse it with the version available from LANL.
00025  *
00026  * Additionally, this program is free software; you can redistribute
00027  * it and/or modify it under the terms of the GNU General Public
00028  * License as published by the Free Software Foundation; version 2 of
00029  * the License. Accordingly, this program is distributed in the hope
00030  * it will be useful, but WITHOUT ANY WARRANTY; without even the
00031  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
00032  * PURPOSE. See the GNU General Public License for more details.
00033  */
00034 
00035 
00036 #include <math.h>
00037 #include <string.h>
00038 #include "coordinates.h"
00039 
00040 
00041 int Coordinates::list_reference_ellipsoids(char *names[], unsigned int *len)
00042 {
00043         int i, size = (*len > _GLOBAL_ELLIPSOIDS) ? _GLOBAL_ELLIPSOIDS : *len;
00044         for (i = 0; i < size; i++) {
00045                 if (names != 0) {
00046                         strcpy(names[i], reference_ellipsoids[i].name);
00047                 }
00048         }
00049         names[i] = 0;
00050 
00051         *len = _GLOBAL_ELLIPSOIDS;
00052         return i;
00053 }
00054 
00055 
00056 int Coordinates::_reference_ellipsoid_index(const char *name)
00057 {
00058         unsigned int i;
00059         for (i = 0; i < _GLOBAL_ELLIPSOIDS; i++) {
00060                 int size = (strlen(name) > 
00061                             strlen(reference_ellipsoids[i].name)) ? 
00062                         strlen(reference_ellipsoids[i].name) : strlen(name);
00063                 if (strncmp(name, reference_ellipsoids[i].name, size) == 0)
00064                         return i;
00065         }
00066         return -1;
00067 }
00068 
00069 
00070 
00071 static inline double __radians2degrees(double radians)
00072 {
00073         return radians * 180 / M_PI;
00074 }
00075 
00076 
00077 static inline double __degrees2radians(double degrees)
00078 {
00079         return degrees * M_PI / 180;
00080 }
00081 
00082 
00083 
00084 void Coordinates::set_ellipsoid(char *type)
00085 {
00086         if (_reference_ellipsoid_index(type) < 0)
00087                 strcpy(_ellipsoid, "WGS 84");
00088         else
00089                 strcpy(_ellipsoid, type);
00090 }
00091 
00092 /* Using spherical trigonometry (< 1m accuracy with long double precision) */
00093 
00094 double Coordinates::_rad_distance(double lat1, double lon1, 
00095                                        double lat2, double lon2)
00096 {
00097         /* assumes called from origin point instance */
00098         double delta_lon = __degrees2radians(lon2) - 
00099                 __degrees2radians(lon1);
00100         double rad_lat1 = __degrees2radians(lat1);
00101         double rad_lat2 = __degrees2radians(lat2);
00102 
00103         double num = sqrt(pow((cos(rad_lat2) * sin(delta_lon)), 2) +
00104                           pow(((cos(rad_lat1) * sin(rad_lat2)) - 
00105                                (sin(rad_lat1) * cos(rad_lat2) * 
00106                                 cos(delta_lon))), 2));
00107         double denom = (sin(rad_lat1) * sin(rad_lat2)) + 
00108                 (cos(rad_lat1) * cos(rad_lat2) * cos(delta_lon));
00109 
00110         return atan2(num, denom);
00111 }
00112 
00113 
00114 double Coordinates::coord_distance(double lat1, double lon1, 
00115                                    double lat2, double lon2)
00116 {
00117         /* assumes called from origin point instance */
00118         int idx = _reference_ellipsoid_index(_ellipsoid);
00119         double a = reference_ellipsoids[idx].equatorial_radius;
00120 
00121         return a * _rad_distance(lat1, lon1, lat2, lon2);
00122 }
00123 
00124 
00125 void Coordinates::coords2meters(double latitude, double longitude,
00126                                 double *x, double *y)
00127 {
00128         /* assumes called from origin point instance */
00129         int idx = _reference_ellipsoid_index(_ellipsoid);
00130         double a = reference_ellipsoids[idx].equatorial_radius;
00131 
00132         double rad_lat1 = __degrees2radians(lat);
00133         double rad_lat2 = __degrees2radians(latitude);
00134         double rad_lon1 = __degrees2radians(lon);
00135         double rad_lon2 = __degrees2radians(longitude);
00136         double delta_lat = rad_lat2 - rad_lat1;
00137         double delta_lon = rad_lon2 - rad_lon1;
00138 
00139         double hypotenuse = _rad_distance(lat, lon, latitude, longitude);
00140 
00141         double bearing = atan2(sin(delta_lon) * cos(rad_lat2),
00142                                cos(rad_lat1) * sin(rad_lat2) - 
00143                                sin(rad_lat1) * cos(rad_lat2) * 
00144                                cos(delta_lon));
00145 
00146         double A = pow(sin((hypotenuse - delta_lat) / 2), 2) + 
00147                 sin(hypotenuse) * sin(delta_lat) * 
00148                 pow(sin(bearing / 2), 2);
00149 
00150         if (rad_lon2 >= rad_lon1)
00151                 *x = a * 2 * atan2(sqrt(A), sqrt(1 - A));
00152         else
00153                 *x = -a * 2 * atan2(sqrt(A), sqrt(1 - A));
00154         *y = a * delta_lat;
00155 }
00156 
00157 
00158 void Coordinates::meters2coords(double x, double y, 
00159                                 double *latitude, double *longitude)
00160 {
00161         /* assumes called from origin point instance */
00162         int idx = _reference_ellipsoid_index(_ellipsoid);
00163         double a = reference_ellipsoids[idx].equatorial_radius;
00164 
00165         double rad_lat1 = __degrees2radians(lat);
00166         double rad_lon1 = __degrees2radians(lon);
00167         double rad_y = y / a;
00168         double rad_x = x / a;
00169 
00170         double rad_dist = sqrt(pow(x, 2) + pow(y, 2)) / a;
00171 //      double rad_bearing = atan2(rad_x, rad_y);  equivalent??
00172         double rad_bearing = atan2(sin(rad_x) * cos(rad_y), 
00173                                    sin(rad_y));
00174 
00175         double rad_lat2 = asin(sin(rad_lat1) * cos(rad_dist) + 
00176                                cos(rad_lat1) * sin(rad_dist) * 
00177                                cos(rad_bearing));
00178         double rad_lon2 = rad_lon1 + 
00179                 atan2(sin(rad_bearing) * sin(rad_dist) * cos(rad_lat1),
00180                       cos(rad_dist) - sin(rad_lat1) * sin(rad_lat2));
00181 
00182         *latitude = __radians2degrees(rad_lat2);
00183         *longitude = __radians2degrees(rad_lon2);
00184 }


© 2007, Los Alamos National Security, LLC.