[mapcode] 23/32: Added self checking code

Stefan Fritsch sf at moszumanska.debian.org
Wed Nov 2 23:27:17 UTC 2016


This is an automated email from the git hooks/post-receive script.

sf pushed a commit to annotated tag v1.33
in repository mapcode.

commit 757d6cdba4b9a89940784aa07b0959c3912e92df
Author: Rijn Buve <rijn at buve.nl>
Date:   Mon Sep 1 14:00:39 2014 +0200

    Added self checking code
---
 mapcode.c | 278 +++++++++++++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 210 insertions(+), 68 deletions(-)

diff --git a/mapcode.c b/mapcode.c
index 98df1f2..1081560 100644
--- a/mapcode.c
+++ b/mapcode.c
@@ -27,7 +27,12 @@
 #include <math.h>
 #include "mapcoder/mapcoder.c"
 
+static const char*  VERSION             = "1.01";
+static const int    SELF_CHECK          = 1;
+static const int    SELF_CHECK_EXIT     = 0;
 
+static const int    NORMAL_ERROR    = 1;
+static const int    INTERNAL_ERROR  = 2;
 
 /**
  * Some global constants to be used.
@@ -35,6 +40,7 @@
 static const double PI              = 3.14159265358979323846;
 static const int    RESULTS_MAX     = 64;
 static const int    SHOW_PROGRESS   = 125;
+static const double DELTA           = 0.001;
 
 
 
@@ -42,10 +48,11 @@ static const int    SHOW_PROGRESS   = 125;
  * These statistics are stored globally so they can be updated easily by the
  * generateAndOutputMapcodes() method.
  */
+static int      totalNrOfPoints         = 0;
+static int      totalNrOfResults        = 0;
 static int      largestNrOfResults      = 0;
 static double   latLargestNrOfResults   = 0.0;
 static double   lonLargestNrOfResults   = 0.0;
-static int      totalNrOfResults        = 0;
 
 
 
@@ -54,7 +61,7 @@ static int      totalNrOfResults        = 0;
  * whenever a incorrect amount or combination of parameters is entered.
  */
 static void usage(const char* appName) {
-    printf("MAPCODE (C library version %s)\n", mapcode_cversion);
+    printf("MAPCODE %s (C library version %s)%s\n", VERSION, mapcode_cversion, SELF_CHECK ? " (self-checking)" : "");
     printf("Copyright (C) 2014 Stichting Mapcode Foundation\n");
     printf("\n");
     printf("Usage:\n");
@@ -69,8 +76,8 @@ static void usage(const char* appName) {
     printf("       encoding will only succeeed if the lat/lon is located in the territory.\n");
     printf("\n");
     printf("    %s [-b | --boundaries]\n", appName);
-    printf("    %s [-g | --grid] <nrPoints>\n", appName);
-    printf("    %s [-r | --random] <nrPoints> [<seed>]\n", appName);
+    printf("    %s [-g | --grid] <nrOfPoints>\n", appName);
+    printf("    %s [-r | --random] <nrOfPoints> [<seed>]\n", appName);
     printf("\n");
     printf("       Create a test set of lat/lon pairs based on the Mapcode boundaries database\n");
     printf("       as a fixed 3D grid or random uniformly distributed set of lat/lons with their\n");
@@ -92,6 +99,9 @@ static void usage(const char* appName) {
     printf("\n     Notes on the use of stdout and stderr:\n");
     printf("\n     stdout: used for outputting 3D point data; stderr: used for statistics.");
     printf("\n     You can redirect stdout to a destination file, while stderr will show progress.\n");
+    printf("\n");
+    printf("       The result code is 0 when no error occurred, 1 if an input error occurred and 2\n");
+    printf("       if an internal error occurred.\n");
 }
 
 
@@ -156,28 +166,116 @@ static void convertLatLonToXYZ(double latDeg, double lonDeg, double* x, double*
 
 
 /**
+ * This methods provides a self check for encoding lat/lon to Mapcode.
+ */
+static void selfCheckLatLonToMapcode(const double lat, double lon, const char* territory, const char* mapcode) {
+    int context = text2tc(territory, 0);
+    char* results[RESULTS_MAX];
+    const double limitLat = (lat < -90.0) ? -90.0 : ((lat > 90.0) ? 90.0 : lat);
+    const double limitLon = (lon < -180.0) ? -180.0 : ((lon > 180.0) ? 180.0 : lon);
+    const int nrResults = coord2mc(results, limitLat, limitLon, context);
+    if (nrResults <= 0) {
+        fprintf(stderr, "internal error: encoding lat/lon to Mapcode failure; "
+            "cannot encode lat=%f, lon=%f (default territory=%s)\n",
+            lat, lon, territory);
+        if (SELF_CHECK_EXIT) {
+            exit(INTERNAL_ERROR);
+        }
+        return;
+    }
+    int found = 0;
+    for (int i = 0; !found && (i < nrResults); ++i) {
+        const char* foundMapcode = results[(i * 2)];
+        const char* foundTerritory = results[(i * 2) + 1];
+        found = ((strcmp(territory, foundTerritory) == 0) && (strcmp(mapcode, foundMapcode) == 0));
+    }
+    if (!found) {
+        fprintf(stderr, "internal error: encoding lat/lon to Mapcode failure; "
+            "Mapcode '%s %s' decodes to lat=%f(%f), lon=%f(%f), "
+            "which does not encode back to '%s %s'\n",
+            territory, mapcode, lat, limitLat, lon, limitLon, territory, mapcode);
+        if (SELF_CHECK_EXIT) {
+            exit(INTERNAL_ERROR);
+        }
+        return;
+    }
+}
+
+
+
+/**
+ * This method provides a self-check for decoding a Mapcode to lat/lon.
+ */
+static void selfCheckMapcodeToLatLon(const char* territory, const char* mapcode,
+    const double lat, const double lon) {
+    double foundLat;
+    double foundLon;
+    int foundContext = text2tc(territory, 0);
+    int err = mc2coord(&foundLat, &foundLon, mapcode, foundContext);
+    if (err != 0) {
+        fprintf(stderr, "internal error: decoding Mapcode to lat/lon failure; "
+            "cannot decode '%s %s')\n", territory, mapcode);
+        if (SELF_CHECK_EXIT) {
+            exit(INTERNAL_ERROR);
+        }
+        return;
+    }
+    double deltaLat = ((foundLat - lat) >= 0.0 ? (foundLat - lat) : -(foundLat - lat));
+    double deltaLon = ((foundLon - lon) >- 0.0 ? (foundLon - lon) : -(foundLon - lon));
+    if (deltaLon > 180.0) {
+        deltaLon = 360.0 - deltaLon;
+    }
+    if ((deltaLat > DELTA) || (deltaLon > DELTA)) {
+        fprintf(stderr, "internal error: decoding Mapcode to lat/lon failure; "
+            "lat=%f, lon=%f produces Mapcode %s %s, "
+            "which decodes to lat=%f (delta=%f), lon=%f (delta=%f)\n",
+            lat, lon, territory, mapcode, foundLat, deltaLat, foundLon, deltaLon);
+        if (SELF_CHECK_EXIT) {
+            exit(INTERNAL_ERROR);
+        }
+        return;
+    }
+}
+
+
+
+/**
  * The method printMapcode() generates and outputs Mapcodes for a lat/lon pair.
  * If iShowError != 0, then encoding errors are output to stderr, otherwise they
  * are ignored.
  */
-static int generateAndOutputMapcodes(double lat, double lon, int iShowError) {
-    const char* results[RESULTS_MAX];
+static void generateAndOutputMapcodes(double lat, double lon, int iShowError) {
+
+    char* results[RESULTS_MAX];
     int context = 0;
     const int nrResults = coord2mc(results, lat, lon, context);
     if (nrResults <= 0) {
         if (iShowError) {
             fprintf(stderr, "error: cannot encode lat=%f, lon=%f)\n", lat, lon);
+            exit(NORMAL_ERROR);
         }
-        return -1;
     }
+
     double x;
     double y;
     double z;
     convertLatLonToXYZ(lat, lon, &x, &y, &z);
     printf("%d %lf %lf %lf %lf %lf\n", nrResults, lat, lon, x, y, z);
     for (int j = 0; j < nrResults; ++j) {
-        printf("%s %s\n", results[(j * 2) + 1], results[(j * 2)]);
+        const char* foundMapcode = results[(j * 2)];
+        const char* foundTerritory = results[(j * 2) + 1];
+
+        // Output result line.
+        printf("%s %s\n", foundTerritory, foundMapcode);
+
+        // Self-checking code to see if encoder produces this Mapcode for the lat/lon.
+        if (SELF_CHECK) {
+            selfCheckLatLonToMapcode(lat, lon, foundTerritory, foundMapcode);
+            selfCheckMapcodeToLatLon(foundTerritory, foundMapcode, lat, lon);
+        }
     }
+
+    // Add empty line.
     printf("\n");
 
     if (nrResults > largestNrOfResults) {
@@ -186,7 +284,44 @@ static int generateAndOutputMapcodes(double lat, double lon, int iShowError) {
         lonLargestNrOfResults = lon;
     }
     totalNrOfResults += nrResults;
-    return nrResults;
+}
+
+
+
+/**
+ * This method resets the statistics counters.
+ */
+static void resetStatistics(int nrOfPoints) {
+    totalNrOfPoints = nrOfPoints;
+    largestNrOfResults = 0;
+    latLargestNrOfResults = 0.0;
+    lonLargestNrOfResults = 0.0;
+}
+
+
+
+/**
+ * This method outputs the statistics.
+ */
+static void outputStatistics() {
+    fprintf(stderr, "\nStatistics:\n");
+    fprintf(stderr, "Total number of 3D points generated     = %d\n", totalNrOfPoints);
+    fprintf(stderr, "Total number of Mapcodes generated      = %d\n", totalNrOfResults);
+    fprintf(stderr, "Average number of Mapcodes per 3D point = %f\n",
+        ((float) totalNrOfResults) / ((float) totalNrOfPoints));
+    fprintf(stderr, "Largest number of results for 1 Mapcode = %d at (%f, %f)\n",
+        largestNrOfResults, latLargestNrOfResults, lonLargestNrOfResults);
+}
+
+
+
+/**
+ * This method shows a progress indication.
+ */
+static void showProgress(int i) {
+    fprintf(stderr, "[%d%%] Processed %d of %d regions (generated %d Mapcodes)...\r",
+        (int) ((((float) i / ((float) totalNrOfPoints)) * 100.0) + 0.5),
+        i, totalNrOfPoints, totalNrOfResults);
 }
 
 
@@ -201,7 +336,7 @@ int main(const int argc, const char** argv)
     const char* appName = argv[0];
     if (argc < 2) {
         usage(appName);
-        return -1;
+        return NORMAL_ERROR;
     }
 
     // First argument: command.
@@ -214,20 +349,34 @@ int main(const int argc, const char** argv)
         if (argc < 4) {
             fprintf(stderr, "error: incorrect number of arguments\n\n");
             usage(appName);
-            return -1;
+            return NORMAL_ERROR;
         }
 
         const char* defaultTerritory = argv[2];
         double lat;
         double lon;
+
+        // Get the territory context.
         int context = text2tc(defaultTerritory, 0);
+
+        // Decode every Mapcode.
         for (int i = 3; i < argc; ++i) {
-            int err = mc2coord(&lat, &lon, argv[i], context);
+
+            // Decode the Mapcode to a lat/lon.
+            const char* mapcode = argv[i];
+            int err = mc2coord(&lat, &lon, mapcode, context);
             if (err != 0) {
-                fprintf(stderr, "error: cannot decode '%s' (default territory='%s')\n", argv[i], argv[2]);
-                return -1;
+                fprintf(stderr, "error: cannot decode '%s %s'\n", defaultTerritory, mapcode);
+                return NORMAL_ERROR;
             }
+
+            // Output the decoded lat/lon.
             printf("%f %f\n", lat, lon);
+
+            // Self-checking code to see if encoder produces this Mapcode for the lat/lon.
+            if (SELF_CHECK) {
+                selfCheckLatLonToMapcode(lat, lon, defaultTerritory, mapcode);
+            }
         }
     }
     else if ((strcmp(cmd, "-e") == 0) || (strcmp(cmd, "--encode") == 0)) {
@@ -238,24 +387,43 @@ int main(const int argc, const char** argv)
         if ((argc != 4) && (argc != 5)) {
             fprintf(stderr, "error: incorrect number of arguments\n\n");
             usage(appName);
-            return -1;
+            return NORMAL_ERROR;
+        }
+        if ((!isdigit(*argv[2]) && (*argv[2] != '-')) || (!isdigit(*argv[3]) && (*argv[3] != '-'))) {
+            fprintf(stderr, "error: latitude and longitude must be numeric\n");
+            usage(appName);
+            return NORMAL_ERROR;
         }
         const double lat = atof(argv[2]);
         const double lon = atof(argv[3]);
 
+        // Get territory context.
         int context = 0;
+        char* defaultTerritory = "AAA";
         if (argc == 5) {
             context = text2tc(argv[4], 0);
+            defaultTerritory = argv[4];
         }
-        const char* results[RESULTS_MAX];
+
+        // Encode the lat/lon to a set of Mapcodes.
+        char* results[RESULTS_MAX];
         const int nrResults = coord2mc(results, lat, lon, context);
         if (nrResults <= 0) {
-            fprintf(stderr, "error: cannot encode lat=%s, lon=%s (default territory=%d)\n",
-                argv[2], argv[3], context);
-            return -1;
+            fprintf(stderr, "error: cannot encode lat=%f, lon=%f (default territory=%s)\n",
+                lat, lon, defaultTerritory);
+            return NORMAL_ERROR;
         }
+
+        // Output the Mapcode.
         for (int i = 0; i < nrResults; ++i) {
-            printf("%s %s\n", results[(i * 2) + 1], results[(i * 2)]);
+            const char* foundMapcode = results[(i * 2)];
+            const char* foundTerritory = results[(i * 2) + 1];
+            printf("%s %s\n", foundTerritory, foundMapcode);
+
+            // Self-checking code to see if decoder produces the lat/lon for all of these Mapcodes.
+            if (SELF_CHECK) {
+                selfCheckMapcodeToLatLon(foundTerritory, foundMapcode, lat, lon);
+            }
         }
     }
     else if ((strcmp(cmd, "-b") == 0) || (strcmp(cmd, "--boundaries") == 0)) {
@@ -266,17 +434,11 @@ int main(const int argc, const char** argv)
         if (argc != 2) {
             fprintf(stderr, "error: incorrect number of arguments\n\n");
             usage(appName);
-            return -1;
+            return NORMAL_ERROR;
         }
 
-        // Statistics.
-        largestNrOfResults = 0;
-        latLargestNrOfResults = 0.0;
-        lonLargestNrOfResults = 0.0;
-        totalNrOfResults = 0;
-
-        int nrPoints = NR_RECS;
-        for (int i = 0; i < nrPoints; ++i) {
+        resetStatistics(NR_RECS);
+        for (int i = 0; i < totalNrOfPoints; ++i) {
             long minLonE6;
             long maxLonE6;
             long minLatE6;
@@ -332,35 +494,28 @@ int main(const int argc, const char** argv)
             generateAndOutputMapcodes(maxLat + 22, (maxLon - minLon) / 2, 0);
 
             if ((i % SHOW_PROGRESS) == 0) {
-                fprintf(stderr, "[%d%%] Processed %d of %d regions (generated %d Mapcodes)...\r",
-                    (int) ((((float) i / ((float) nrPoints)) * 100.0) + 0.5),
-                    i, nrPoints, totalNrOfResults);
+                showProgress(i);
             }
         }
-        fprintf(stderr, "\nStatistics:\n");
-        fprintf(stderr, "Total number of 3D points generated     = %d\n", nrPoints);
-        fprintf(stderr, "Total number of Mapcodes generated      = %d\n", totalNrOfResults);
-        fprintf(stderr, "Average number of Mapcodes per 3D point = %f\n", ((float) totalNrOfResults) / ((float) nrPoints));
-        fprintf(stderr, "Largest number of results for 1 Mapcode = %d at (%f, %f)\n",
-            largestNrOfResults, latLargestNrOfResults, lonLargestNrOfResults);
+        outputStatistics();
     }
     else if ((strcmp(cmd, "-g") == 0) || (strcmp(cmd, "--grid") == 0) ||
         (strcmp(cmd, "-r") == 0) || (strcmp(cmd, "--random") == 0)) {
 
         // ------------------------------------------------------------------
-        // Generate grid test set:    [-g | --grid]   <nrPoints>
-        // Generate uniform test set: [-r | --random] <nrPoints> [<seed>]
+        // Generate grid test set:    [-g | --grid]   <nrOfPoints>
+        // Generate uniform test set: [-r | --random] <nrOfPoints> [<seed>]
         // ------------------------------------------------------------------
         if ((argc < 3) || (argc > 4)) {
             fprintf(stderr, "error: incorrect number of arguments\n\n");
             usage(appName);
-            return -1;
+            return NORMAL_ERROR;
         }
-        const int nrPoints = atoi(argv[2]);
-        if (nrPoints < 1) {
+        int nrOfPoints = atoi(argv[2]);
+        if (nrOfPoints < 1) {
             fprintf(stderr, "error: total number of points to generate must be >= 1\n\n");
             usage(appName);
-            return -1;
+            return NORMAL_ERROR;
         }
         int random = (strcmp(cmd, "-r") == 0) || (strcmp(cmd, "--random") == 0);
         if (random) {
@@ -376,20 +531,18 @@ int main(const int argc, const char** argv)
             if (argc > 3) {
                 fprintf(stderr, "error: cannot specify seed for -g/--grid\n\n");
                 usage(appName);
-                return -1;
+                return NORMAL_ERROR;
             }
         }
 
         // Statistics.
-        largestNrOfResults = 0;
-        latLargestNrOfResults = 0.0;
-        lonLargestNrOfResults = 0.0;
-        totalNrOfResults = 0;
+        resetStatistics(nrOfPoints);
+        int totalNrOfResults = 0;
 
         int gridX = 0;
         int gridY = 0;
-        int line = round(sqrt(nrPoints));
-        for (int i = 0; i < nrPoints; ++i) {
+        int line = round(sqrt(totalNrOfPoints));
+        for (int i = 0; i < totalNrOfPoints; ++i) {
             double lat;
             double lon;
             double unit1;
@@ -413,25 +566,13 @@ int main(const int argc, const char** argv)
             }
 
             unitToLatLonDeg(unit1, unit2, &lat, &lon);
-            const int nrResults = generateAndOutputMapcodes(lat, lon, 1);
-            if (nrResults > largestNrOfResults) {
-                largestNrOfResults = nrResults;
-                latLargestNrOfResults = lat;
-                lonLargestNrOfResults = lon;
-            }
-            totalNrOfResults += nrResults;
+            generateAndOutputMapcodes(lat, lon, 1);
+
             if ((i % SHOW_PROGRESS) == 0) {
-                fprintf(stderr, "[%d%%] Created %d of %d 3D %s data points (generated %d Mapcodes)...\r",
-                    (int) ((((float) i / ((float) nrPoints)) * 100.0) + 0.5),
-                    i, nrPoints, random ? "random" : "grid", totalNrOfResults);
+                showProgress(i);
             }
         }
-        fprintf(stderr, "\nStatistics:\n");
-        fprintf(stderr, "Total number of 3D points generated     = %d\n", nrPoints);
-        fprintf(stderr, "Total number of Mapcodes generated      = %d\n", totalNrOfResults);
-        fprintf(stderr, "Average number of Mapcodes per 3D point = %f\n", ((float) totalNrOfResults) / ((float) nrPoints));
-        fprintf(stderr, "Largest number of results for 1 Mapcode = %d at (%f, %f)\n",
-            largestNrOfResults, latLargestNrOfResults, lonLargestNrOfResults);
+        outputStatistics();
     }
     else {
 
@@ -439,7 +580,8 @@ int main(const int argc, const char** argv)
         // Usage.
         // ------------------------------------------------------------------
         usage(appName);
-        return -1;
+        return NORMAL_ERROR;
     }
+    fprintf(stderr, "done\n");
     return 0;
 }

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/mapcode.git



More information about the Pkg-grass-devel mailing list