]> git.street.me.uk Git - andy/viking.git/blobdiff - src/coords.c
[DOC] Mention map tilesize configuration.
[andy/viking.git] / src / coords.c
index 40f2e8e920fd7d7829c2906045b5974a4b6dae72..f6dae4c78b1f9a0611136aa6a99fb8737fa19872 100644 (file)
@@ -35,12 +35,42 @@ renaming functions and defining LatLon and UTM structs.
 ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 ** SUCH DAMAGE.
 */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
 
+#ifdef HAVE_STDLIB_H
 #include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
 #include <string.h>
+#endif
+#ifdef HAVE_MATH_H
 #include <math.h>
+#endif
 
+#include "coords.h"
+#ifdef HAVE_VIKING
 #include "viking.h"
+#include "globals.h"
+#else
+#define DEG2RAD(x) ((x)*(M_PI/180))
+#define RAD2DEG(x) ((x)*(180/M_PI))
+#endif
+#include "degrees_converters.h"
+#include "misc/fpconv.h"
+
+/**
+ *
+ */
+void a_coords_dtostr_buffer ( double d, char buffer[COORDS_STR_BUFFER_SIZE] )
+{
+  int str_len = fpconv_dtoa(d, buffer);
+  if ( str_len < COORDS_STR_BUFFER_SIZE )
+    buffer[str_len] = '\0';
+  else
+    buffer[COORDS_STR_BUFFER_SIZE-1] = '\0';
+}
 
 /**
  * Convert a double to a string WITHOUT LOCALE.
@@ -52,19 +82,12 @@ renaming functions and defining LatLon and UTM structs.
  */
 char *a_coords_dtostr ( double d )
 {
-  /* In order to ignore locale, we do all the stuff manually */
-  double integer, decimal;
-  integer = trunc(d);
-
-  /* 6 decimals are sufficient (~0,1m) */
-  /* Cf. http://www.tbs-sct.gc.ca/rpm-gbi/guides/Latlong_f.asp */
-  decimal = d - integer;
-  decimal = decimal * 1000000;
-  decimal = trunc ( decimal );
-  decimal = fabs ( decimal );
-
-  /* Format */
-  return g_strdup_printf ( "%g.%06g", integer, decimal );
+  gchar *buffer = g_malloc(G_ASCII_DTOSTR_BUF_SIZE*sizeof(gchar));
+  // Note that this doesn't necessary produce the shortest string
+  //g_ascii_formatd (buffer, G_ASCII_DTOSTR_BUF_SIZE, "%.9lf", (gdouble)d);
+  // Thus use third party code:
+  a_coords_dtostr_buffer ( d, buffer );
+  return buffer;
 }
 
 #define PIOVER180 0.01745329252
@@ -97,11 +120,14 @@ double a_coords_utm_diff( const struct UTM *utm1, const struct UTM *utm2 )
 double a_coords_latlon_diff ( const struct LatLon *ll1, const struct LatLon *ll2 )
 {
   static struct LatLon tmp1, tmp2;
+  gdouble tmp3;
   tmp1.lat = ll1->lat * PIOVER180;
   tmp1.lon = ll1->lon * PIOVER180;
   tmp2.lat = ll2->lat * PIOVER180;
   tmp2.lon = ll2->lon * PIOVER180;
-  return EquatorialRadius * acos(sin(tmp1.lat)*sin(tmp2.lat)+cos(tmp1.lat)*cos(tmp2.lat)*cos(tmp1.lon-tmp2.lon));
+  tmp3 = EquatorialRadius * acos(sin(tmp1.lat)*sin(tmp2.lat)+cos(tmp1.lat)*cos(tmp2.lat)*cos(tmp1.lon-tmp2.lon));
+  // For very small differences we can sometimes get NaN returned
+  return isnan(tmp3)?0:tmp3;
 }
 
 void a_coords_latlon_to_utm( const struct LatLon *latlon, struct UTM *utm )
@@ -125,8 +151,8 @@ void a_coords_latlon_to_utm( const struct LatLon *latlon, struct UTM *utm )
        longitude -= 360.0;
 
     /* Now convert. */
-    lat_rad = latitude * M_PI / 180.0;
-    long_rad = longitude * M_PI / 180.0;
+    lat_rad = DEG2RAD(latitude);
+    long_rad = DEG2RAD(longitude);
     zone = (int) ( ( longitude + 180 ) / 6 ) + 1;
     if ( latitude >= 56.0 && latitude < 64.0 &&
         longitude >= 3.0 && longitude < 12.0 )
@@ -140,7 +166,7 @@ void a_coords_latlon_to_utm( const struct LatLon *latlon, struct UTM *utm )
        else if ( longitude >= 33.0 && longitude < 42.0 ) zone = 37;
        }
     long_origin = ( zone - 1 ) * 6 - 180 + 3;  /* +3 puts origin in middle of zone */
-    long_origin_rad = long_origin * M_PI / 180.0;
+    long_origin_rad = DEG2RAD(long_origin);
     eccPrimeSquared = EccentricitySquared / ( 1.0 - EccentricitySquared );
     N = EquatorialRadius / sqrt( 1.0 - EccentricitySquared * sin( lat_rad ) * sin( lat_rad ) );
     T = tan( lat_rad ) * tan( lat_rad );
@@ -205,7 +231,6 @@ void a_coords_utm_to_latlon( const struct UTM *utm, struct LatLon *latlon )
     double N1, T1, C1, R1, D, M;
     double long_origin;
     double mu, phi1_rad;
-    int northernHemisphere;    /* 1 for northern hemisphere, 0 for southern */
     double latitude, longitude;
 
     northing = utm->northing;
@@ -216,13 +241,11 @@ void a_coords_utm_to_latlon( const struct UTM *utm, struct LatLon *latlon )
     /* Now convert. */
     x = easting - 500000.0;    /* remove 500000 meter offset */
     y = northing;
-    if ( ( *letter - 'N' ) >= 0 )
-       northernHemisphere = 1; /* northern hemisphere */
-    else
-       {
-       northernHemisphere = 0; /* southern hemisphere */
-       y -= 10000000.0;        /* remove 1e7 meter offset */
-       }
+    if ( ( *letter - 'N' ) < 0 ) {
+      /* southern hemisphere */
+      y -= 10000000.0; /* remove 1e7 meter offset */
+    }
+
     long_origin = ( zone - 1 ) * 6 - 180 + 3;  /* +3 puts origin in middle of zone */
     eccPrimeSquared = EccentricitySquared / ( 1.0 - EccentricitySquared );
     e1 = ( 1.0 - sqrt( 1.0 - EccentricitySquared ) ) / ( 1.0 + sqrt( 1.0 - EccentricitySquared ) );
@@ -235,9 +258,9 @@ void a_coords_utm_to_latlon( const struct UTM *utm, struct LatLon *latlon )
     R1 = EquatorialRadius * ( 1.0 - EccentricitySquared ) / pow( 1.0 - EccentricitySquared * sin( phi1_rad ) * sin( phi1_rad ), 1.5 );
     D = x / ( N1 * K0 );
     latitude = phi1_rad - ( N1 * tan( phi1_rad ) / R1 ) * ( D * D / 2 -( 5 + 3 * T1 + 10 * C1 - 4 * C1 * C1 - 9 * eccPrimeSquared ) * D * D * D * D / 24 + ( 61 + 90 * T1 + 298 * C1 + 45 * T1 * T1 - 252 * eccPrimeSquared - 3 * C1 * C1 ) * D * D * D * D * D * D / 720 );
-    latitude = latitude * 180.0 / M_PI;
+    latitude = RAD2DEG(latitude);
     longitude = ( D - ( 1 + 2 * T1 + C1 ) * D * D * D / 6 + ( 5 - 2 * C1 + 28 * T1 - 3 * C1 * C1 + 8 * eccPrimeSquared + 24 * T1 * T1 ) * D * D * D * D * D / 120 ) / cos( phi1_rad );
-    longitude = long_origin + longitude * 180.0 / M_PI;
+    longitude = long_origin + RAD2DEG(longitude);
 
     /* Show results. */
 
@@ -245,3 +268,37 @@ void a_coords_utm_to_latlon( const struct UTM *utm, struct LatLon *latlon )
     latlon->lon = longitude;
 
     }
+
+void a_coords_latlon_to_string ( const struct LatLon *latlon,
+                                gchar **lat,
+                                gchar **lon )
+{
+  g_return_if_fail ( latlon != NULL );
+#ifdef HAVE_VIKING
+  vik_degree_format_t format = a_vik_get_degree_format ();
+
+  switch (format) {
+  case VIK_DEGREE_FORMAT_DDD:
+    *lat = convert_lat_dec_to_ddd ( latlon->lat );
+    *lon = convert_lon_dec_to_ddd ( latlon->lon );
+    break;
+  case VIK_DEGREE_FORMAT_DMM:
+    *lat = convert_lat_dec_to_dmm ( latlon->lat );
+    *lon = convert_lon_dec_to_dmm ( latlon->lon );
+    break;
+  case VIK_DEGREE_FORMAT_DMS:
+    *lat = convert_lat_dec_to_dms ( latlon->lat );
+    *lon = convert_lon_dec_to_dms ( latlon->lon );
+    break;
+  case VIK_DEGREE_FORMAT_RAW:
+    *lat = g_strdup_printf ( "%.6f", latlon->lat );
+    *lon = g_strdup_printf ( "%.6f", latlon->lon );
+    break;
+  default:
+    g_critical("Houston, we've had a problem. format=%d", format);
+  }
+#else
+  *lat = convert_lat_dec_to_ddd ( latlon->lat );
+  *lon = convert_lon_dec_to_ddd ( latlon->lon );
+#endif
+}