|
| 1 | +/** |
| 2 | + * Copyright (C) 2014 Stichting Mapcode Foundation |
| 3 | + * For terms of use refer to http://www.mapcode.com/downloads.html |
| 4 | + */ |
| 5 | + |
| 6 | +#include <stdio.h> |
| 7 | +#include <math.h> |
| 8 | +#include "mapcoder/mapcoder.c" |
| 9 | + |
| 10 | +static const double PI = 3.14159265358979323846; |
| 11 | + |
| 12 | +static void usage(const char* appName) { |
| 13 | + printf("Usage: \n"); |
| 14 | + printf(" %s [-d | --decode] <default-country-ISO3> <mapcode> [<mapcode> ...]\n", appName); |
| 15 | + printf("\n"); |
| 16 | + printf(" Decode a Mapcode to a lat/lon. The default country code is used if\n"); |
| 17 | + printf(" the Mapcode is a shorthand local code\n"); |
| 18 | + printf("\n"); |
| 19 | + printf(" %s [-e | --encode] <lat:-90..90> <lon:-180..180> [country-ISO3]>\n", appName); |
| 20 | + printf("\n"); |
| 21 | + printf(" Encode a lat/lon to a Mapcode. If the country code is specified, the\n"); |
| 22 | + printf(" encoding will only succeeed if the lat/lon is located in the country.\n"); |
| 23 | + printf("\n"); |
| 24 | + printf(" %s [-g | --generate] <nrPoints> [<seed>]\n", appName); |
| 25 | + printf("\n"); |
| 26 | + printf(" Create a test set of a number of uniformly distributed lat/lon pairs,\n"); |
| 27 | + printf(" 3D x/y/z points and their Mapcodes). The output format is:\n"); |
| 28 | + printf(" <nr> <lat> <lon> <x> <y> <z>\n"); |
| 29 | + printf(" <country> <mapcode> (repeated 'nr' rtimes)\n"); |
| 30 | + printf(" <1 empty line>\n"); |
| 31 | + printf("\n"); |
| 32 | + printf(" The points will be uniformly distributed over the 3D surface of the Earth\n"); |
| 33 | + printf(" rather than using uniformly distributed lat/lon values.\n"); |
| 34 | + printf(" Ranges:\n"); |
| 35 | + printf(" nr > 1 lat = -90..90 lon = -180..180 x,y,z = -1..1\n"); |
| 36 | + printf("\n"); |
| 37 | +} |
| 38 | + |
| 39 | +int main(const int argc, const char** argv) |
| 40 | +{ |
| 41 | + // Provide usage message if no arguments specified. |
| 42 | + const char* appName = argv[0]; |
| 43 | + if (argc < 2) { |
| 44 | + usage(appName); |
| 45 | + return -1; |
| 46 | + } |
| 47 | + |
| 48 | + // First argument: command. |
| 49 | + const char* cmd = argv[1]; |
| 50 | + if ((strcmp(cmd, "-d") == 0) || (strcmp(cmd, "--decode") == 0)) { |
| 51 | + |
| 52 | + // ------------------------------------------------------------------ |
| 53 | + // Decode: [-d | --decode] <default-country-ISO3> <mapcode> [<mapcode> ...] |
| 54 | + // ------------------------------------------------------------------ |
| 55 | + if (argc < 4) { |
| 56 | + usage(appName); |
| 57 | + return -1; |
| 58 | + } |
| 59 | + |
| 60 | + const char* defaultCountry = argv[2]; |
| 61 | + double lat; |
| 62 | + double lon; |
| 63 | + int context = text2tc(defaultCountry, 0); |
| 64 | + for (int i = 3; i < argc; ++i) { |
| 65 | + int err = mc2coord(&lat, &lon, argv[i], context); |
| 66 | + if (err != 0) { |
| 67 | + printf("error: cannot decode '%s' (default country='%s')\n", argv[i], argv[1]); |
| 68 | + return -1; |
| 69 | + } |
| 70 | + printf("%f %f\n", lat, lon); |
| 71 | + } |
| 72 | + } |
| 73 | + else if ((strcmp(cmd, "-e") == 0) || (strcmp(cmd, "--encode") == 0)) { |
| 74 | + |
| 75 | + // ------------------------------------------------------------------ |
| 76 | + // Encode: [-e | --encode] <lat:-90..90> <lon:-180..180> [country-ISO3]> |
| 77 | + // ------------------------------------------------------------------ |
| 78 | + if ((argc != 4) && (argc != 5)) { |
| 79 | + usage(appName); |
| 80 | + return -1; |
| 81 | + } |
| 82 | + const double lat = atof(argv[2]); |
| 83 | + const double lon = atof(argv[3]); |
| 84 | + |
| 85 | + int context = 0; |
| 86 | + if (argc == 4) { |
| 87 | + context = text2tc(argv[4], 0); |
| 88 | + } |
| 89 | + const char* results[32]; |
| 90 | + printf("e: %f %f %d\n", lat, lon, context); |
| 91 | + const int nrResults = coord2mc(results, lat, lon, context); |
| 92 | + if (nrResults <= 0) { |
| 93 | + printf("error: cannot encode lat=%s, lon=%s (default country=%d)\n", argv[2], argv[3], context); |
| 94 | + return -1; |
| 95 | + } |
| 96 | + for (int i = 0; i < nrResults; ++i) { |
| 97 | + printf("%s %s\n", results[(i * 2) + 1], results[(i * 2)]); |
| 98 | + } |
| 99 | + } |
| 100 | + else if ((strcmp(cmd, "-g") == 0) || (strcmp(cmd, "--generate") == 0)) { |
| 101 | + |
| 102 | + // ------------------------------------------------------------------ |
| 103 | + // Generate uniform test set: [-g | --generate] <nrPoints> [<seed>] |
| 104 | + // ------------------------------------------------------------------ |
| 105 | + if ((argc != 3) && (argc != 4)) { |
| 106 | + usage(appName); |
| 107 | + return -1; |
| 108 | + } |
| 109 | + const int nrPoints = atoi(argv[2]); |
| 110 | + |
| 111 | + if (argc == 4) { |
| 112 | + const int seed = atoi(argv[3]); |
| 113 | + srand(seed); |
| 114 | + } |
| 115 | + else { |
| 116 | + srand(time(0)); |
| 117 | + } |
| 118 | + const char* results[32]; |
| 119 | + int context = 0; |
| 120 | + for (int i = 0; i < nrPoints; ++i) { |
| 121 | + |
| 122 | + // Calculate uniformly distributed 3D point on sphere (radius = 1.0): |
| 123 | + // http://mathproofs.blogspot.co.il/2005/04/uniform-random-distribution-on-sphere.html |
| 124 | + const double unitRand = ((double) rand()) / RAND_MAX; |
| 125 | + const double theta0 = (2.0 * PI) * unitRand; |
| 126 | + const double theta1 = acos(1.0 - (2.0 * unitRand)); |
| 127 | + const double x = sin(theta0) * sin(theta1); |
| 128 | + const double y = cos(theta0) * sin(theta1); |
| 129 | + const double z = cos(theta1); |
| 130 | + |
| 131 | + // Convert Carthesian 3D point into lat/lon (radius = 1.0): |
| 132 | + // http://stackoverflow.com/questions/1185408/converting-from-longitude-latitude-to-cartesian-coordinates |
| 133 | + const double latRad = asin(z); |
| 134 | + const double lonRad = atan2(y, x); |
| 135 | + |
| 136 | + // Convert radians to degrees. |
| 137 | + const double lat = latRad * (180.0 / PI); |
| 138 | + const double lon = lonRad * (180.0 / PI); |
| 139 | + |
| 140 | + printf("e: %f %f %d\n", lat, lon, context); |
| 141 | + const int nrResults = coord2mc(results, lat, lon, context); |
| 142 | + if (nrResults <= 0) { |
| 143 | + printf("error: cannot encode lat=%f, lon=%f)\n", lat, lon); |
| 144 | + return -1; |
| 145 | + } |
| 146 | + printf("%d %f %f %f %f %f\n", nrResults, lat, lon, x, y, z); |
| 147 | + for (int i = 0; i < nrResults; ++i) { |
| 148 | + printf("%s %s\n", results[(i * 2) + 1], results[(i * 2)]); |
| 149 | + } |
| 150 | + printf("\n"); |
| 151 | + } |
| 152 | + } |
| 153 | + else { |
| 154 | + |
| 155 | + // ------------------------------------------------------------------ |
| 156 | + // Usage. |
| 157 | + // ------------------------------------------------------------------ |
| 158 | + usage(appName); |
| 159 | + return -1; |
| 160 | + } |
| 161 | + return 0; |
| 162 | +} |
0 commit comments