From f2131c03d6c312206ca060a79f27ed858c3afb3d Mon Sep 17 00:00:00 2001 From: David Ellis Date: Wed, 9 Oct 2024 21:32:38 -0500 Subject: [PATCH] greatCircleDistanceRads --- src/apps/filters/h3.c | 67 +++++++++++++++++++++++++++ tests/cli/greatCircleDistanceRads.txt | 4 ++ 2 files changed, 71 insertions(+) create mode 100644 tests/cli/greatCircleDistanceRads.txt diff --git a/src/apps/filters/h3.c b/src/apps/filters/h3.c index 8d045d8e3..52390b620 100644 --- a/src/apps/filters/h3.c +++ b/src/apps/filters/h3.c @@ -2188,6 +2188,72 @@ SUBCOMMAND(pentagonCount, "Returns 12") { return E_SUCCESS; } +SUBCOMMAND(greatCircleDistanceRads, + "Calculates the 'great circle' or 'haversine' distance between two " + "lat, lng points, in radians") { + char filename[1024] = {0}; // More than Windows, lol + Arg filenameArg = {.names = {"-f", "--file"}, + .scanFormat = "%1023c", + .valueName = "FILENAME", + .value = &filename, + .helpText = + "The file to load the coordinates from. Use -- to " + "read from stdin."}; + char coordinateStr[1501] = {0}; + Arg coordinateStrArg = { + .names = {"-c", "--coordinates"}, + .scanFormat = "%1500c", + .valueName = "ARRAY", + .value = &coordinateStr, + .helpText = + "The array of coordinates to convert. Up to 1500 characters."}; + Arg *args[] = {&greatCircleDistanceRadsArg, &filenameArg, &coordinateStrArg, + &helpArg}; + PARSE_SUBCOMMAND(argc, argv, args); + if (!filenameArg.found && !coordinateStrArg.found) { + fprintf( + stderr, + "You must provide either a file to read from or a coordinate array " + "to use greatCircleDistanceRads"); + exit(1); + } + FILE *fp = 0; + bool isStdin = false; + if (filenameArg.found) { + if (strcmp(filename, "--") == 0) { + fp = stdin; + isStdin = true; + } else { + fp = fopen(filename, "r"); + } + if (fp == 0) { + fprintf(stderr, "The specified file does not exist."); + exit(1); + } + // Do the initial population of data from the file + if (fread(coordinateStr, 1, 1500, fp) == 0) { + fprintf(stderr, "The specified file is empty."); + exit(1); + } + } + GeoPolygon polygon = {0}; + H3Error err = polygonStringToGeoPolygon(fp, coordinateStr, &polygon); + if (fp != 0 && !isStdin) { + fclose(fp); + } + if (err != E_SUCCESS) { + return err; + } + if (polygon.numHoles > 0 || polygon.geoloop.numVerts != 2) { + fprintf(stderr, "Only two pairs of coordinates should be provided."); + exit(1); + } + double distance = H3_EXPORT(greatCircleDistanceRads)( + &polygon.geoloop.verts[0], &polygon.geoloop.verts[1]); + printf("%.10lf\n", distance); + return E_SUCCESS; +} + SUBCOMMAND(greatCircleDistanceKm, "Calculates the 'great circle' or 'haversine' distance between two " "lat, lng points, in kilometers") { @@ -2395,6 +2461,7 @@ SUBCOMMAND_INDEX(getNumCells) SUBCOMMAND_INDEX(getRes0Cells) SUBCOMMAND_INDEX(getPentagons) SUBCOMMAND_INDEX(pentagonCount) +SUBCOMMAND_INDEX(greatCircleDistanceRads) SUBCOMMAND_INDEX(greatCircleDistanceKm) SUBCOMMAND_INDEX(greatCircleDistanceM) diff --git a/tests/cli/greatCircleDistanceRads.txt b/tests/cli/greatCircleDistanceRads.txt new file mode 100644 index 000000000..af4d2b499 --- /dev/null +++ b/tests/cli/greatCircleDistanceRads.txt @@ -0,0 +1,4 @@ +add_h3_cli_test(testCliGreatCircleDistanceRadsArg "greatCircleDistanceRads -c '[[0, 1], [1, 2]]'" "0.0246820564") +add_h3_cli_test(testCliGreatCircleDistanceRadsFile "greatCircleDistanceRads -f ${PROJECT_SOURCE_DIR}/tests/inputfiles/great_circle_distance.txt" "0.0246820564") +add_h3_cli_test(testCliGreatCircleDistanceRadsStdin "greatCircleDistanceRads -f -- < ${PROJECT_SOURCE_DIR}/tests/inputfiles/great_circle_distance.txt" "0.0246820564") +add_h3_cli_test(testCliGreatCircleDistanceRadsBadArg "greatCircleDistanceRads -c '[[0, 1]]' 2>&1" "Only two pairs of coordinates should be provided.")