geotaxis.c 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <stdbool.h>
  4. #include <string.h>
  5. #include <math.h>
  6. #include <errno.h>
  7. struct coord {
  8. double lat;
  9. double lon;
  10. };
  11. const char *usage_str = "Usage: %s LATITUDE LONGITUDE DISTANCE BEARING\n\
  12. \n\
  13. Calculate destination from starting LATITUDE and LONGITUDE and going DISTANCE in BEARING direction.\n\
  14. \n\
  15. Arguments:\n\
  16. \t* BEARING is degrees deasil (i.e. clockwise) from North.\n\
  17. \t* DIRECTION is in kilometres.\n\
  18. \t* All arguments will be parsed as doubles, i.e. use 30.5 not 30°30'0\".\n";
  19. void usage(FILE *out, const char *whoami) {
  20. fprintf(out, usage_str, whoami);
  21. }
  22. double parse_arg(const char *arg) {
  23. char *endptr;
  24. errno = 0;
  25. double val = strtod(arg, &endptr);
  26. if(errno != 0) {
  27. fprintf(stderr, "Error %d: %s\n(While attempting to parse '%s')\n", errno, strerror(errno), arg);
  28. exit(1);
  29. }
  30. if(endptr == arg) {
  31. fprintf(stderr, "Error while parsing '%s': not a number?\n", arg);
  32. exit(1);
  33. }
  34. return val;
  35. }
  36. double deg2rad(double deg) {
  37. return deg*M_PI/180.0;
  38. }
  39. double rad2deg(double rad) {
  40. return rad*180.0/M_PI;
  41. }
  42. void forward_haversine(struct coord *dest, const struct coord *origin, const double D, const double b) {
  43. /*
  44. Based on:
  45. * https://stackoverflow.com/a/7835325/10210798
  46. * https://www.movable-type.co.uk/scripts/latlong.html
  47. This function expects and returns radians.
  48. */
  49. // Save calculating the same thing more than once
  50. double d = D/6378.1;
  51. double cos_lat_1 = cos(origin->lat);
  52. double sin_lat_1 = sin(origin->lat);
  53. double cos_d = cos(d);
  54. double sin_d = sin(d);
  55. dest->lat = asin(sin_lat_1*cos_d+cos_lat_1*sin_d*cos(b));
  56. dest->lon = origin->lon + atan2(sin(b)*sin_d*cos_lat_1, cos_d-sin_lat_1*sin(dest->lat));
  57. }
  58. int main(int argc, char **argv) {
  59. if(argc != 5) {
  60. usage(stderr, argv[0]);
  61. exit(1);
  62. }
  63. struct coord origin, dest;
  64. origin.lat = deg2rad(parse_arg(argv[1]));
  65. origin.lon = deg2rad(parse_arg(argv[2]));
  66. double distance = parse_arg(argv[3]);
  67. double bearing = deg2rad(parse_arg(argv[4]));
  68. forward_haversine(&dest, &origin, distance, bearing);
  69. printf("%f %f\n", rad2deg(dest.lat), rad2deg(dest.lon));
  70. return 0;
  71. }