00001
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
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
00093
00094 double Coordinates::_rad_distance(double lat1, double lon1,
00095 double lat2, double lon2)
00096 {
00097
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
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
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
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
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 }