From a434272c2ab851d405a73c10523763e5c02542a9 Mon Sep 17 00:00:00 2001 From: David Ellis Date: Wed, 16 Oct 2024 12:30:17 -0500 Subject: [PATCH] All remaining subcommands for the h3 cli program (#924) * areNeighborCells * cellsToDirectedEdge * isValidDirectedEdge * getDirectedEdgeOrigin * getDirectedEdgeDestination * directedEdgeToCells * originToDirectedEdges * directedEdgeToBoundary * cellToVertex * cellToVertexes * vertexToLatLng * isValidVertex * degsToRads radsToDegs * getHexagonAreaAvgKm2 * getHexagonAreaAvgM2 * cellAreaRads2 * cellAreaKm2 * cellAreaM2 * getHexagonEdgeLengthAvgKm * getHexagonEdgeLengthAvgM * edgeLengthKm * edgeLengthM * edgeLengthRads * getNumCells * getRes0Cells * getPentagons * pentagonCount * greatCircleDistanceKm * greatCircleDistanceM * greatCircleDistanceRads * describeH3Error * Add some forgotten free() calls * Fix missing free()s in error paths * Add some rounding to a test that's failing on MacOS on ARM * Update src/apps/filters/h3.c Co-authored-by: Isaac Brodsky * Apply suggestions from code review Co-authored-by: Isaac Brodsky * BUFFER_SIZE for a few more constants --------- Co-authored-by: Isaac Brodsky --- src/apps/filters/h3.c | 843 +++++++++++++++++++++ tests/cli/areNeighborCells.txt | 3 + tests/cli/cellAreaKm2.txt | 2 + tests/cli/cellAreaM2.txt | 2 + tests/cli/cellAreaRads2.txt | 2 + tests/cli/cellToVertex.txt | 2 + tests/cli/cellToVertexes.txt | 2 + tests/cli/cellsToDirectedEdge.txt | 2 + tests/cli/degsToRads.txt | 1 + tests/cli/describeH3Error.txt | 4 + tests/cli/directedEdgeToBoundary.txt | 2 + tests/cli/directedEdgeToCells.txt | 2 + tests/cli/edgeLengthKm.txt | 2 + tests/cli/edgeLengthM.txt | 2 + tests/cli/edgeLengthRads.txt | 2 + tests/cli/getDirectedEdgeDestination.txt | 2 + tests/cli/getDirectedEdgeOrigin.txt | 2 + tests/cli/getHexagonAreaAvgKm2.txt | 2 + tests/cli/getHexagonAreaAvgM2.txt | 2 + tests/cli/getHexagonEdgeLengthAvgKm.txt | 2 + tests/cli/getHexagonEdgeLengthAvgM.txt | 2 + tests/cli/getNumCells.txt | 2 + tests/cli/getPentagons.txt | 2 + tests/cli/getRes0Cells.txt | 1 + tests/cli/greatCircleDistanceKm.txt | 4 + tests/cli/greatCircleDistanceM.txt | 4 + tests/cli/greatCircleDistanceRads.txt | 4 + tests/cli/isValidDirectedEdge.txt | 2 + tests/cli/isValidVertex.txt | 2 + tests/cli/originToDirectedEdges.txt | 2 + tests/cli/pentagonCount.txt | 1 + tests/cli/radsToDegs.txt | 1 + tests/cli/vertexToLatLng.txt | 2 + tests/inputfiles/great_circle_distance.txt | 1 + 34 files changed, 913 insertions(+) create mode 100644 tests/cli/areNeighborCells.txt create mode 100644 tests/cli/cellAreaKm2.txt create mode 100644 tests/cli/cellAreaM2.txt create mode 100644 tests/cli/cellAreaRads2.txt create mode 100644 tests/cli/cellToVertex.txt create mode 100644 tests/cli/cellToVertexes.txt create mode 100644 tests/cli/cellsToDirectedEdge.txt create mode 100644 tests/cli/degsToRads.txt create mode 100644 tests/cli/describeH3Error.txt create mode 100644 tests/cli/directedEdgeToBoundary.txt create mode 100644 tests/cli/directedEdgeToCells.txt create mode 100644 tests/cli/edgeLengthKm.txt create mode 100644 tests/cli/edgeLengthM.txt create mode 100644 tests/cli/edgeLengthRads.txt create mode 100644 tests/cli/getDirectedEdgeDestination.txt create mode 100644 tests/cli/getDirectedEdgeOrigin.txt create mode 100644 tests/cli/getHexagonAreaAvgKm2.txt create mode 100644 tests/cli/getHexagonAreaAvgM2.txt create mode 100644 tests/cli/getHexagonEdgeLengthAvgKm.txt create mode 100644 tests/cli/getHexagonEdgeLengthAvgM.txt create mode 100644 tests/cli/getNumCells.txt create mode 100644 tests/cli/getPentagons.txt create mode 100644 tests/cli/getRes0Cells.txt create mode 100644 tests/cli/greatCircleDistanceKm.txt create mode 100644 tests/cli/greatCircleDistanceM.txt create mode 100644 tests/cli/greatCircleDistanceRads.txt create mode 100644 tests/cli/isValidDirectedEdge.txt create mode 100644 tests/cli/isValidVertex.txt create mode 100644 tests/cli/originToDirectedEdges.txt create mode 100644 tests/cli/pentagonCount.txt create mode 100644 tests/cli/radsToDegs.txt create mode 100644 tests/cli/vertexToLatLng.txt create mode 100644 tests/inputfiles/great_circle_distance.txt diff --git a/src/apps/filters/h3.c b/src/apps/filters/h3.c index 3f061a093..5a76b1213 100644 --- a/src/apps/filters/h3.c +++ b/src/apps/filters/h3.c @@ -1632,6 +1632,811 @@ SUBCOMMAND(cellsToMultiPolygon, return E_SUCCESS; } +/// Directed edge subcommands + +SUBCOMMAND(areNeighborCells, + "Determines if the provided H3 cells are neighbors (have a shared " + "border)") { + H3Index origin, destination; + Arg originCellArg = {.names = {"-o", "--origin"}, + .required = true, + .scanFormat = "%" PRIx64, + .valueName = "CELL", + .value = &origin, + .helpText = "Origin H3 Cell"}; + Arg destinationCellArg = {.names = {"-d", "--destination"}, + .required = true, + .scanFormat = "%" PRIx64, + .valueName = "CELL", + .value = &destination, + .helpText = "Destination H3 Cell"}; + Arg *args[] = {&areNeighborCellsArg, &originCellArg, &destinationCellArg, + &helpArg}; + PARSE_SUBCOMMAND(argc, argv, args); + int areNeighbors = 0; + H3Error err = + H3_EXPORT(areNeighborCells)(origin, destination, &areNeighbors); + if (err != E_SUCCESS) { + return err; + } + printf(areNeighbors ? "true\n" : "false\n"); + return E_SUCCESS; +} + +SUBCOMMAND(cellsToDirectedEdge, + "Converts neighboring cells into a directed edge index (or errors " + "if they are not neighbors)") { + H3Index origin, destination; + Arg originCellArg = {.names = {"-o", "--origin"}, + .required = true, + .scanFormat = "%" PRIx64, + .valueName = "CELL", + .value = &origin, + .helpText = "Origin H3 Cell"}; + Arg destinationCellArg = {.names = {"-d", "--destination"}, + .required = true, + .scanFormat = "%" PRIx64, + .valueName = "CELL", + .value = &destination, + .helpText = "Destination H3 Cell"}; + Arg *args[] = {&cellsToDirectedEdgeArg, &originCellArg, &destinationCellArg, + &helpArg}; + PARSE_SUBCOMMAND(argc, argv, args); + H3Index out = 0; + H3Error err = H3_EXPORT(cellsToDirectedEdge)(origin, destination, &out); + if (err != E_SUCCESS) { + return err; + } + printf("%" PRIx64 "\n", out); + return E_SUCCESS; +} + +SUBCOMMAND(isValidDirectedEdge, + "Checks if the provided H3 directed edge is actually valid") { + DEFINE_CELL_ARG(cell, cellArg); + Arg *args[] = {&isValidDirectedEdgeArg, &helpArg, &cellArg}; + PARSE_SUBCOMMAND(argc, argv, args); + bool isValid = H3_EXPORT(isValidDirectedEdge)(cell); + printf("%s", isValid ? "true\n" : "false\n"); + return E_SUCCESS; +} + +SUBCOMMAND(getDirectedEdgeOrigin, + "Returns the origin cell from the directed edge") { + DEFINE_CELL_ARG(cell, cellArg); + Arg *args[] = {&getDirectedEdgeOriginArg, &cellArg, &helpArg}; + PARSE_SUBCOMMAND(argc, argv, args); + H3Index out = 0; + H3Error err = H3_EXPORT(getDirectedEdgeOrigin)(cell, &out); + if (err != E_SUCCESS) { + return err; + } + printf("%" PRIx64 "\n", out); + return E_SUCCESS; +} + +SUBCOMMAND(getDirectedEdgeDestination, + "Returns the destination cell from the directed edge") { + DEFINE_CELL_ARG(cell, cellArg); + Arg *args[] = {&getDirectedEdgeDestinationArg, &cellArg, &helpArg}; + PARSE_SUBCOMMAND(argc, argv, args); + H3Index out = 0; + H3Error err = H3_EXPORT(getDirectedEdgeDestination)(cell, &out); + if (err != E_SUCCESS) { + return err; + } + printf("%" PRIx64 "\n", out); + return E_SUCCESS; +} + +SUBCOMMAND( + directedEdgeToCells, + "Returns the origin, destination pair of cells from the directed edge") { + DEFINE_CELL_ARG(cell, cellArg); + Arg *args[] = {&directedEdgeToCellsArg, &cellArg, &helpArg}; + PARSE_SUBCOMMAND(argc, argv, args); + H3Index out[2] = {0}; + H3Error err = H3_EXPORT(directedEdgeToCells)(cell, &out[0]); + if (err != E_SUCCESS) { + return err; + } + printf("[%" PRIx64 ", %" PRIx64 "]\n", out[0], out[1]); + return E_SUCCESS; +} + +SUBCOMMAND(originToDirectedEdges, + "Returns all of the directed edges from the specified origin cell") { + DEFINE_CELL_ARG(cell, cellArg); + Arg *args[] = {&originToDirectedEdgesArg, &cellArg, &helpArg}; + PARSE_SUBCOMMAND(argc, argv, args); + H3Index out[6] = {0}; + // This one is pretty loose about the inputs it accepts, so let's validate + // for it + bool isValid = H3_EXPORT(isValidCell)(cell); + if (!isValid) { + return E_CELL_INVALID; + } + H3Error err = H3_EXPORT(originToDirectedEdges)(cell, &out[0]); + if (err != E_SUCCESS) { + return err; + } + printf("["); + bool hasPrinted = false; + for (int i = 0; i < 6; i++) { + if (out[i] > 0) { + if (hasPrinted) { + printf(", "); + } + printf("%" PRIx64, out[i]); + hasPrinted = true; + } + } + printf("]\n"); + return E_SUCCESS; +} + +SUBCOMMAND(directedEdgeToBoundary, + "Provides the coordinates defining the directed edge") { + DEFINE_CELL_ARG(cell, cellArg); + Arg *args[] = {&directedEdgeToBoundaryArg, &cellArg, &helpArg}; + PARSE_SUBCOMMAND(argc, argv, args); + CellBoundary cb = {0}; + H3Error err = H3_EXPORT(directedEdgeToBoundary)(cell, &cb); + if (err) { + return err; + } + // Using WKT formatting for the output. TODO: Add support for JSON + // formatting + printf("POLYGON(("); + for (int i = 0; i < cb.numVerts; i++) { + LatLng *ll = &cb.verts[i]; + printf("%.10lf %.10lf, ", H3_EXPORT(radsToDegs)(ll->lng), + H3_EXPORT(radsToDegs)(ll->lat)); + } + // WKT has the first and last points match, so re-print the first one + printf("%.10lf %.10lf))\n", H3_EXPORT(radsToDegs)(cb.verts[0].lng), + H3_EXPORT(radsToDegs)(cb.verts[0].lat)); + return E_SUCCESS; +} + +/// Vertex subcommands + +SUBCOMMAND(cellToVertex, + "Returns the vertex for the specified cell and vertex index. Must " + "be 0-5 for hexagons, 0-4 for pentagons") { + DEFINE_CELL_ARG(cell, cellArg); + int vertIndex = 0; + Arg vertIndexArg = { + .names = {"-v", "--vertex"}, + .required = true, + .scanFormat = "%d", + .valueName = "INDEX", + .value = &vertIndex, + .helpText = "Vertex index number. 0-5 for hexagons, 0-4 for pentagons"}; + Arg *args[] = {&cellToVertexArg, &cellArg, &vertIndexArg, &helpArg}; + PARSE_SUBCOMMAND(argc, argv, args); + // This function also doesn't sanitize its inputs correctly + bool isValid = H3_EXPORT(isValidCell)(cell); + if (!isValid) { + return E_CELL_INVALID; + } + H3Index out = 0; + H3Error err = H3_EXPORT(cellToVertex)(cell, vertIndex, &out); + if (err) { + return err; + } + printf("%" PRIx64 "\n", out); + return E_SUCCESS; +} + +SUBCOMMAND(cellToVertexes, + "Returns all of the vertexes from the specified cell") { + DEFINE_CELL_ARG(cell, cellArg); + Arg *args[] = {&cellToVertexesArg, &cellArg, &helpArg}; + PARSE_SUBCOMMAND(argc, argv, args); + H3Index out[6] = {0}; + // This one is pretty loose about the inputs it accepts, so let's validate + // for it + bool isValid = H3_EXPORT(isValidCell)(cell); + if (!isValid) { + return E_CELL_INVALID; + } + H3Error err = H3_EXPORT(cellToVertexes)(cell, &out[0]); + if (err != E_SUCCESS) { + return err; + } + printf("["); + bool hasPrinted = false; + for (int i = 0; i < 6; i++) { + if (out[i] > 0) { + if (hasPrinted) { + printf(", "); + } + printf("%" PRIx64, out[i]); + hasPrinted = true; + } + } + printf("]\n"); + return E_SUCCESS; +} + +SUBCOMMAND(vertexToLatLng, "Returns the lat, lng pair for the given vertex") { + DEFINE_CELL_ARG(cell, cellArg); + Arg *args[] = {&vertexToLatLngArg, &cellArg, &helpArg}; + PARSE_SUBCOMMAND(argc, argv, args); + bool isValid = H3_EXPORT(isValidVertex)(cell); + if (!isValid) { + return E_VERTEX_INVALID; + } + LatLng ll; + H3Error err = H3_EXPORT(vertexToLatLng)(cell, &ll); + if (err) { + return err; + } + // Using WKT formatting for the output. TODO: Add support for JSON + // formatting + printf("POINT(%.10lf %.10lf)\n", H3_EXPORT(radsToDegs)(ll.lng), + H3_EXPORT(radsToDegs)(ll.lat)); + return E_SUCCESS; +} + +SUBCOMMAND(isValidVertex, + "Checks if the provided H3 vertex is actually valid") { + DEFINE_CELL_ARG(cell, cellArg); + Arg *args[] = {&isValidVertexArg, &helpArg, &cellArg}; + PARSE_SUBCOMMAND(argc, argv, args); + bool isValid = H3_EXPORT(isValidVertex)(cell); + printf("%s", isValid ? "true\n" : "false\n"); + return E_SUCCESS; +} + +/// Miscellaneous subcommands + +SUBCOMMAND(degsToRads, "Converts degrees to radians") { + double deg = 0; + Arg degArg = {.names = {"-d", "--degree"}, + .required = true, + .scanFormat = "%lf", + .valueName = "DEG", + .value = °, + .helpText = "Angle in degrees"}; + Arg *args[] = {°sToRadsArg, °Arg, &helpArg}; + PARSE_SUBCOMMAND(argc, argv, args); + printf("%.10lf\n", H3_EXPORT(degsToRads)(deg)); + return E_SUCCESS; +} + +SUBCOMMAND(radsToDegs, "Converts radians to degrees") { + double rad = 0; + Arg radArg = {.names = {"-r", "--radian"}, + .required = true, + .scanFormat = "%lf", + .valueName = "RAD", + .value = &rad, + .helpText = "Angle in radians"}; + Arg *args[] = {&radsToDegsArg, &radArg, &helpArg}; + PARSE_SUBCOMMAND(argc, argv, args); + printf("%.10lf\n", H3_EXPORT(radsToDegs)(rad)); + return E_SUCCESS; +} + +SUBCOMMAND(getHexagonAreaAvgKm2, + "The average area in square kilometers for a hexagon of a given " + "resolution (excludes pentagons)") { + int res = 0; + Arg resArg = {.names = {"-r", "--resolution"}, + .required = true, + .scanFormat = "%d", + .valueName = "res", + .value = &res, + .helpText = "Resolution, 0-15 inclusive."}; + Arg *args[] = {&getHexagonAreaAvgKm2Arg, &resArg, &helpArg}; + PARSE_SUBCOMMAND(argc, argv, args); + double area = 0; + H3Error err = H3_EXPORT(getHexagonAreaAvgKm2)(res, &area); + if (err) { + return err; + } + printf("%.10lf\n", area); + return E_SUCCESS; +} + +SUBCOMMAND(getHexagonAreaAvgM2, + "The average area in square meters for a hexagon of a given " + "resolution (excludes pentagons)") { + int res = 0; + Arg resArg = {.names = {"-r", "--resolution"}, + .required = true, + .scanFormat = "%d", + .valueName = "res", + .value = &res, + .helpText = "Resolution, 0-15 inclusive."}; + Arg *args[] = {&getHexagonAreaAvgM2Arg, &resArg, &helpArg}; + PARSE_SUBCOMMAND(argc, argv, args); + double area = 0; + H3Error err = H3_EXPORT(getHexagonAreaAvgM2)(res, &area); + if (err) { + return err; + } + printf("%.10lf\n", area); + return E_SUCCESS; +} + +SUBCOMMAND(cellAreaRads2, + "The exact area of a specific cell in square radians") { + DEFINE_CELL_ARG(cell, cellArg); + Arg *args[] = {&cellAreaRads2Arg, &cellArg, &helpArg}; + PARSE_SUBCOMMAND(argc, argv, args); + // This one is pretty loose about the inputs it accepts, so let's validate + // for it + bool isValid = H3_EXPORT(isValidCell)(cell); + if (!isValid) { + return E_CELL_INVALID; + } + double area = 0; + H3Error err = H3_EXPORT(cellAreaRads2)(cell, &area); + if (err) { + return err; + } + printf("%.10lf\n", area); + return E_SUCCESS; +} + +SUBCOMMAND(cellAreaKm2, + "The exact area of a specific cell in square kilometers") { + DEFINE_CELL_ARG(cell, cellArg); + Arg *args[] = {&cellAreaKm2Arg, &cellArg, &helpArg}; + PARSE_SUBCOMMAND(argc, argv, args); + // This one is pretty loose about the inputs it accepts, so let's validate + // for it + bool isValid = H3_EXPORT(isValidCell)(cell); + if (!isValid) { + return E_CELL_INVALID; + } + double area = 0; + H3Error err = H3_EXPORT(cellAreaKm2)(cell, &area); + if (err) { + return err; + } + printf("%.10lf\n", area); + return E_SUCCESS; +} + +SUBCOMMAND(cellAreaM2, "The exact area of a specific cell in square meters") { + DEFINE_CELL_ARG(cell, cellArg); + Arg *args[] = {&cellAreaM2Arg, &cellArg, &helpArg}; + PARSE_SUBCOMMAND(argc, argv, args); + // This one is pretty loose about the inputs it accepts, so let's validate + // for it + bool isValid = H3_EXPORT(isValidCell)(cell); + if (!isValid) { + return E_CELL_INVALID; + } + double area = 0; + H3Error err = H3_EXPORT(cellAreaM2)(cell, &area); + if (err) { + return err; + } + printf("%.10lf\n", area); + return E_SUCCESS; +} + +SUBCOMMAND(getHexagonEdgeLengthAvgKm, + "The average hexagon edge length in kilometers of a given " + "resolution (excludes pentagons)") { + int res = 0; + Arg resArg = {.names = {"-r", "--resolution"}, + .required = true, + .scanFormat = "%d", + .valueName = "res", + .value = &res, + .helpText = "Resolution, 0-15 inclusive."}; + Arg *args[] = {&getHexagonEdgeLengthAvgKmArg, &resArg, &helpArg}; + PARSE_SUBCOMMAND(argc, argv, args); + double area = 0; + H3Error err = H3_EXPORT(getHexagonEdgeLengthAvgKm)(res, &area); + if (err) { + return err; + } + printf("%.10lf\n", area); + return E_SUCCESS; +} + +SUBCOMMAND(getHexagonEdgeLengthAvgM, + "The average hexagon edge length in meters of a given " + "resolution (excludes pentagons)") { + int res = 0; + Arg resArg = {.names = {"-r", "--resolution"}, + .required = true, + .scanFormat = "%d", + .valueName = "res", + .value = &res, + .helpText = "Resolution, 0-15 inclusive."}; + Arg *args[] = {&getHexagonEdgeLengthAvgMArg, &resArg, &helpArg}; + PARSE_SUBCOMMAND(argc, argv, args); + double area = 0; + H3Error err = H3_EXPORT(getHexagonEdgeLengthAvgM)(res, &area); + if (err) { + return err; + } + printf("%.10lf\n", area); + return E_SUCCESS; +} + +SUBCOMMAND(edgeLengthRads, + "The exact edge length of a specific directed edge in radians") { + DEFINE_CELL_ARG(cell, cellArg); + Arg *args[] = {&edgeLengthRadsArg, &cellArg, &helpArg}; + PARSE_SUBCOMMAND(argc, argv, args); + // This one is pretty loose about the inputs it accepts, so let's validate + // for it + bool isValid = H3_EXPORT(isValidDirectedEdge)(cell); + if (!isValid) { + return E_DIR_EDGE_INVALID; + } + double length = 0; + H3Error err = H3_EXPORT(edgeLengthRads)(cell, &length); + if (err) { + return err; + } + printf("%.10lf\n", length); + return E_SUCCESS; +} + +SUBCOMMAND(edgeLengthKm, + "The exact edge length of a specific directed edge in kilometers") { + DEFINE_CELL_ARG(cell, cellArg); + Arg *args[] = {&edgeLengthKmArg, &cellArg, &helpArg}; + PARSE_SUBCOMMAND(argc, argv, args); + // This one is pretty loose about the inputs it accepts, so let's validate + // for it + bool isValid = H3_EXPORT(isValidDirectedEdge)(cell); + if (!isValid) { + return E_DIR_EDGE_INVALID; + } + double length = 0; + H3Error err = H3_EXPORT(edgeLengthKm)(cell, &length); + if (err) { + return err; + } + printf("%.10lf\n", length); + return E_SUCCESS; +} + +SUBCOMMAND(edgeLengthM, + "The exact edge length of a specific directed edge in meters") { + DEFINE_CELL_ARG(cell, cellArg); + Arg *args[] = {&edgeLengthMArg, &cellArg, &helpArg}; + PARSE_SUBCOMMAND(argc, argv, args); + // This one is pretty loose about the inputs it accepts, so let's validate + // for it + bool isValid = H3_EXPORT(isValidDirectedEdge)(cell); + if (!isValid) { + return E_DIR_EDGE_INVALID; + } + double length = 0; + H3Error err = H3_EXPORT(edgeLengthM)(cell, &length); + if (err) { + return err; + } + printf("%.10lf\n", length); + return E_SUCCESS; +} + +SUBCOMMAND(getNumCells, + "The number of unique H3 cells for a specified resolution") { + int res = 0; + Arg resArg = {.names = {"-r", "--resolution"}, + .required = true, + .scanFormat = "%d", + .valueName = "res", + .value = &res, + .helpText = "Resolution, 0-15 inclusive."}; + Arg *args[] = {&getNumCellsArg, &resArg, &helpArg}; + PARSE_SUBCOMMAND(argc, argv, args); + int64_t numCells = 0; + H3Error err = H3_EXPORT(getNumCells)(res, &numCells); + if (err) { + return err; + } + printf("%" PRId64 "\n", numCells); + return E_SUCCESS; +} + +SUBCOMMAND(getRes0Cells, "Returns all of the resolution 0 cells") { + Arg *args[] = {&getRes0CellsArg, &helpArg}; + PARSE_SUBCOMMAND(argc, argv, args); + H3Index *out = calloc(122, sizeof(H3Index)); + H3Error err = H3_EXPORT(getRes0Cells)(out); + if (err != E_SUCCESS) { + free(out); + return err; + } + printf("["); + bool hasPrinted = false; + for (int i = 0; i < 122; i++) { + if (out[i] > 0) { + if (hasPrinted) { + printf(", "); + } + printf("%" PRIx64, out[i]); + hasPrinted = true; + } + } + printf("]\n"); + free(out); + return E_SUCCESS; +} + +SUBCOMMAND(getPentagons, + "Returns all of the pentagons at the specified resolution") { + int res = 0; + Arg resArg = {.names = {"-r", "--resolution"}, + .required = true, + .scanFormat = "%d", + .valueName = "res", + .value = &res, + .helpText = "Resolution, 0-15 inclusive."}; + Arg *args[] = {&getPentagonsArg, &resArg, &helpArg}; + PARSE_SUBCOMMAND(argc, argv, args); + H3Index *out = calloc(12, sizeof(H3Index)); + H3Error err = H3_EXPORT(getPentagons)(res, out); + if (err != E_SUCCESS) { + free(out); + return err; + } + printf("["); + bool hasPrinted = false; + for (int i = 0; i < 12; i++) { + if (out[i] > 0) { + if (hasPrinted) { + printf(", "); + } + printf("%" PRIx64, out[i]); + hasPrinted = true; + } + } + printf("]\n"); + free(out); + return E_SUCCESS; +} + +SUBCOMMAND(pentagonCount, "Returns 12") { + Arg *args[] = {&pentagonCountArg, &helpArg}; + PARSE_SUBCOMMAND(argc, argv, args); + printf("12\n"); + 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, BUFFER_SIZE, 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); + for (int i = 0; i < polygon.numHoles; i++) { + free(polygon.holes[i].verts); + } + free(polygon.holes); + free(polygon.geoloop.verts); + return E_SUCCESS; +} + +SUBCOMMAND(greatCircleDistanceKm, + "Calculates the 'great circle' or 'haversine' distance between two " + "lat, lng points, in kilometers") { + 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[] = {&greatCircleDistanceKmArg, &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 greatCircleDistanceKm"); + 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, BUFFER_SIZE, 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(greatCircleDistanceKm)( + &polygon.geoloop.verts[0], &polygon.geoloop.verts[1]); + printf("%.10lf\n", distance); + for (int i = 0; i < polygon.numHoles; i++) { + free(polygon.holes[i].verts); + } + free(polygon.holes); + free(polygon.geoloop.verts); + return E_SUCCESS; +} + +SUBCOMMAND(greatCircleDistanceM, + "Calculates the 'great circle' or 'haversine' distance between two " + "lat, lng points, in meters") { + 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[] = {&greatCircleDistanceMArg, &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 greatCircleDistanceM"); + 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, BUFFER_SIZE, 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(greatCircleDistanceM)( + &polygon.geoloop.verts[0], &polygon.geoloop.verts[1]); + printf("%.10lf\n", distance); + for (int i = 0; i < polygon.numHoles; i++) { + free(polygon.holes[i].verts); + } + free(polygon.holes); + free(polygon.geoloop.verts); + return E_SUCCESS; +} + +SUBCOMMAND(describeH3Error, + "Returns a description of the provided H3 error code number, or " + "indicates the number is itself invalid.") { + H3Error err = E_SUCCESS; + Arg errArg = {.names = {"-e", "--error"}, + .required = true, + .scanFormat = "%d", + .valueName = "CODE", + .value = &err, + .helpText = "H3 Error code to describe"}; + Arg *args[] = {&describeH3ErrorArg, &errArg, &helpArg}; + PARSE_SUBCOMMAND(argc, argv, args); + printf("%s\n", H3_EXPORT(describeH3Error)(err)); + return E_SUCCESS; +} + // TODO: Is there any way to avoid this particular piece of duplication? SUBCOMMANDS_INDEX @@ -1674,6 +2479,44 @@ SUBCOMMAND_INDEX(polygonToCells) SUBCOMMAND_INDEX(maxPolygonToCellsSize) SUBCOMMAND_INDEX(cellsToMultiPolygon) +/// Directed Edge subcommands +SUBCOMMAND_INDEX(areNeighborCells) +SUBCOMMAND_INDEX(cellsToDirectedEdge) +SUBCOMMAND_INDEX(isValidDirectedEdge) +SUBCOMMAND_INDEX(getDirectedEdgeOrigin) +SUBCOMMAND_INDEX(getDirectedEdgeDestination) +SUBCOMMAND_INDEX(directedEdgeToCells) +SUBCOMMAND_INDEX(originToDirectedEdges) +SUBCOMMAND_INDEX(directedEdgeToBoundary) + +/// Vertex subcommands +SUBCOMMAND_INDEX(cellToVertex) +SUBCOMMAND_INDEX(cellToVertexes) +SUBCOMMAND_INDEX(vertexToLatLng) +SUBCOMMAND_INDEX(isValidVertex) + +/// Miscellaneous subcommands +SUBCOMMAND_INDEX(degsToRads) +SUBCOMMAND_INDEX(radsToDegs) +SUBCOMMAND_INDEX(getHexagonAreaAvgKm2) +SUBCOMMAND_INDEX(getHexagonAreaAvgM2) +SUBCOMMAND_INDEX(cellAreaRads2) +SUBCOMMAND_INDEX(cellAreaKm2) +SUBCOMMAND_INDEX(cellAreaM2) +SUBCOMMAND_INDEX(getHexagonEdgeLengthAvgKm) +SUBCOMMAND_INDEX(getHexagonEdgeLengthAvgM) +SUBCOMMAND_INDEX(edgeLengthRads) +SUBCOMMAND_INDEX(edgeLengthKm) +SUBCOMMAND_INDEX(edgeLengthM) +SUBCOMMAND_INDEX(getNumCells) +SUBCOMMAND_INDEX(getRes0Cells) +SUBCOMMAND_INDEX(getPentagons) +SUBCOMMAND_INDEX(pentagonCount) +SUBCOMMAND_INDEX(greatCircleDistanceRads) +SUBCOMMAND_INDEX(greatCircleDistanceKm) +SUBCOMMAND_INDEX(greatCircleDistanceM) +SUBCOMMAND_INDEX(describeH3Error) + END_SUBCOMMANDS_INDEX int main(int argc, char *argv[]) { diff --git a/tests/cli/areNeighborCells.txt b/tests/cli/areNeighborCells.txt new file mode 100644 index 000000000..368aecbec --- /dev/null +++ b/tests/cli/areNeighborCells.txt @@ -0,0 +1,3 @@ +add_h3_cli_test(testCliAreNeighborCells "areNeighborCells -o 85283473fffffff -d 85283477fffffff" "true") +add_h3_cli_test(testCliAreNotNeighborCells "areNeighborCells -o 85283473fffffff -d 85283472fffffff" "false") +add_h3_cli_test(testCliAreNeighborNotCells "areNeighborCells -o 85283473fffffff -d 852834727fffffff 2>&1" "Error 5: Cell argument was not valid") diff --git a/tests/cli/cellAreaKm2.txt b/tests/cli/cellAreaKm2.txt new file mode 100644 index 000000000..4e976f3ad --- /dev/null +++ b/tests/cli/cellAreaKm2.txt @@ -0,0 +1,2 @@ +add_h3_cli_test(testCliCellAreaKm2 "cellAreaKm2 -c 85283473fffffff" "265.0925581283") +add_h3_cli_test(testCliNotCellAreaKm2 "cellAreaKm2 -c 115283473fffffff 2>&1" "Error 5: Cell argument was not valid") diff --git a/tests/cli/cellAreaM2.txt b/tests/cli/cellAreaM2.txt new file mode 100644 index 000000000..004b7c7cb --- /dev/null +++ b/tests/cli/cellAreaM2.txt @@ -0,0 +1,2 @@ +add_h3_cli_test(testCliCellAreaM2 "cellAreaM2 -c 85283473fffffff | xargs printf '%.3f'" "265092558.128") +add_h3_cli_test(testCliNotCellAreaM2 "cellAreaM2 -c 115283473fffffff 2>&1" "Error 5: Cell argument was not valid") diff --git a/tests/cli/cellAreaRads2.txt b/tests/cli/cellAreaRads2.txt new file mode 100644 index 000000000..20f865805 --- /dev/null +++ b/tests/cli/cellAreaRads2.txt @@ -0,0 +1,2 @@ +add_h3_cli_test(testCliCellAreaRads2 "cellAreaRads2 -c 85283473fffffff" "0.0000065310") +add_h3_cli_test(testCliNotCellAreaRads2 "cellAreaRads2 -c 115283473fffffff 2>&1" "Error 5: Cell argument was not valid") diff --git a/tests/cli/cellToVertex.txt b/tests/cli/cellToVertex.txt new file mode 100644 index 000000000..3efa6d2fd --- /dev/null +++ b/tests/cli/cellToVertex.txt @@ -0,0 +1,2 @@ +add_h3_cli_test(testCliCellToVertex "cellToVertex -c 85283473fffffff -v 0" "22528340bfffffff") +add_h3_cli_test(testCliNotCellToVertex "cellToVertex -c 115283473fffffff -v 0 2>&1" "Error 5: Cell argument was not valid") diff --git a/tests/cli/cellToVertexes.txt b/tests/cli/cellToVertexes.txt new file mode 100644 index 000000000..52f24bb79 --- /dev/null +++ b/tests/cli/cellToVertexes.txt @@ -0,0 +1,2 @@ +add_h3_cli_test(testCliCellToVertexes "cellToVertexes -c 85283473fffffff" "[22528340bfffffff, 235283447fffffff, 205283463fffffff, 255283463fffffff, 22528340ffffffff, 23528340bfffffff]") +add_h3_cli_test(testCliNotCellToVertexes "cellToVertexes -c 115283473fffffff 2>&1" "Error 5: Cell argument was not valid") diff --git a/tests/cli/cellsToDirectedEdge.txt b/tests/cli/cellsToDirectedEdge.txt new file mode 100644 index 000000000..9e0c8656b --- /dev/null +++ b/tests/cli/cellsToDirectedEdge.txt @@ -0,0 +1,2 @@ +add_h3_cli_test(testCliCellsToDirectedEdge "cellsToDirectedEdge -o 85283473fffffff -d 85283477fffffff" "115283473fffffff") +add_h3_cli_test(testCliCellsNotToDirectedEdge "cellsToDirectedEdge -o 85283473fffffff -d 85283472fffffff 2>&1" "Error 11: Cell arguments were not neighbors") diff --git a/tests/cli/degsToRads.txt b/tests/cli/degsToRads.txt new file mode 100644 index 000000000..a59b5299e --- /dev/null +++ b/tests/cli/degsToRads.txt @@ -0,0 +1 @@ +add_h3_cli_test(testCliDegsToRads "degsToRads -d 180" "3.1415926536") diff --git a/tests/cli/describeH3Error.txt b/tests/cli/describeH3Error.txt new file mode 100644 index 000000000..fcc55b990 --- /dev/null +++ b/tests/cli/describeH3Error.txt @@ -0,0 +1,4 @@ +add_h3_cli_test(testCliDescribeH3Error0 "describeH3Error -e 0" "Success") +add_h3_cli_test(testCliDescribeH3Error10 "describeH3Error -e 10" "Duplicate input") +add_h3_cli_test(testCliDescribeH3Error13 "describeH3Error -e 13" "Memory allocation failed") +add_h3_cli_test(testCliDescribeH3Error100 "describeH3Error -e 100" "Invalid error code") diff --git a/tests/cli/directedEdgeToBoundary.txt b/tests/cli/directedEdgeToBoundary.txt new file mode 100644 index 000000000..537f75927 --- /dev/null +++ b/tests/cli/directedEdgeToBoundary.txt @@ -0,0 +1,2 @@ +add_h3_cli_test(testCliDirectedEdgeToBoundary "directedEdgeToBoundary -c 115283473fffffff" "POLYGON((-122.0377349643 37.4201286777, -122.0904289290 37.3375560844, -122.0377349643 37.4201286777))") +add_h3_cli_test(testCliNotDirectedEdgeToBoundary "directedEdgeToBoundary -c 85283473fffffff 2>&1" "Error 6: Directed edge argument was not valid") diff --git a/tests/cli/directedEdgeToCells.txt b/tests/cli/directedEdgeToCells.txt new file mode 100644 index 000000000..c5f23c695 --- /dev/null +++ b/tests/cli/directedEdgeToCells.txt @@ -0,0 +1,2 @@ +add_h3_cli_test(testCliDirectedEdgeToCells "directedEdgeToCells -c 115283473fffffff" "[85283473fffffff, 85283477fffffff]") +add_h3_cli_test(testCliNotDirectedEdgeToCells "directedEdgeToCells -c 85283473fffffff 2>&1" "Error 6: Directed edge argument was not valid") diff --git a/tests/cli/edgeLengthKm.txt b/tests/cli/edgeLengthKm.txt new file mode 100644 index 000000000..3c0cc8b4d --- /dev/null +++ b/tests/cli/edgeLengthKm.txt @@ -0,0 +1,2 @@ +add_h3_cli_test(testCliEdgeLengthKm "edgeLengthKm -c 115283473fffffff" "10.2947360862") +add_h3_cli_test(testCliNotEdgeLengthKm "edgeLengthKm -c 85283473fffffff 2>&1" "Error 6: Directed edge argument was not valid") diff --git a/tests/cli/edgeLengthM.txt b/tests/cli/edgeLengthM.txt new file mode 100644 index 000000000..173cbe0f9 --- /dev/null +++ b/tests/cli/edgeLengthM.txt @@ -0,0 +1,2 @@ +add_h3_cli_test(testCliEdgeLengthM "edgeLengthM -c 115283473fffffff" "10294.7360861995") +add_h3_cli_test(testCliNotEdgeLengthM "edgeLengthM -c 85283473fffffff 2>&1" "Error 6: Directed edge argument was not valid") diff --git a/tests/cli/edgeLengthRads.txt b/tests/cli/edgeLengthRads.txt new file mode 100644 index 000000000..8e3fbffb8 --- /dev/null +++ b/tests/cli/edgeLengthRads.txt @@ -0,0 +1,2 @@ +add_h3_cli_test(testCliEdgeLengthRads "edgeLengthRads -c 115283473fffffff" "0.0016158726") +add_h3_cli_test(testCliNotEdgeLengthRads "edgeLengthRads -c 85283473fffffff 2>&1" "Error 6: Directed edge argument was not valid") diff --git a/tests/cli/getDirectedEdgeDestination.txt b/tests/cli/getDirectedEdgeDestination.txt new file mode 100644 index 000000000..7a67f2a0b --- /dev/null +++ b/tests/cli/getDirectedEdgeDestination.txt @@ -0,0 +1,2 @@ +add_h3_cli_test(testCliGetDirectedEdgeDestination "getDirectedEdgeDestination -c 115283473fffffff" "85283477fffffff") +add_h3_cli_test(testCliDoNotGetDirectedEdgeDestination "getDirectedEdgeDestination -c 85283473fffffff 2>&1" "Error 6: Directed edge argument was not valid") diff --git a/tests/cli/getDirectedEdgeOrigin.txt b/tests/cli/getDirectedEdgeOrigin.txt new file mode 100644 index 000000000..770d26264 --- /dev/null +++ b/tests/cli/getDirectedEdgeOrigin.txt @@ -0,0 +1,2 @@ +add_h3_cli_test(testCliGetDirectedEdgeOrigin "getDirectedEdgeOrigin -c 115283473fffffff" "85283473fffffff") +add_h3_cli_test(testCliDoNotGetDirectedEdgeOrigin "getDirectedEdgeOrigin -c 85283473fffffff 2>&1" "Error 6: Directed edge argument was not valid") diff --git a/tests/cli/getHexagonAreaAvgKm2.txt b/tests/cli/getHexagonAreaAvgKm2.txt new file mode 100644 index 000000000..c1a4c6946 --- /dev/null +++ b/tests/cli/getHexagonAreaAvgKm2.txt @@ -0,0 +1,2 @@ +add_h3_cli_test(testCliGetHexagonAreaAvgKm2 "getHexagonAreaAvgKm2 -r 0" "4357449.4160783831") +add_h3_cli_test(testCliDontGetHexagonAreaAvgKm2 "getHexagonAreaAvgKm2 -r 20 2>&1" "Error 4: Resolution argument was outside of acceptable range") diff --git a/tests/cli/getHexagonAreaAvgM2.txt b/tests/cli/getHexagonAreaAvgM2.txt new file mode 100644 index 000000000..ecd48074d --- /dev/null +++ b/tests/cli/getHexagonAreaAvgM2.txt @@ -0,0 +1,2 @@ +add_h3_cli_test(testCliGetHexagonAreaAvgM2 "getHexagonAreaAvgM2 -r 0" "4357449416078.3901367188") +add_h3_cli_test(testCliDontGetHexagonAreaAvgM2 "getHexagonAreaAvgM2 -r 20 2>&1" "Error 4: Resolution argument was outside of acceptable range") diff --git a/tests/cli/getHexagonEdgeLengthAvgKm.txt b/tests/cli/getHexagonEdgeLengthAvgKm.txt new file mode 100644 index 000000000..44b9f0c47 --- /dev/null +++ b/tests/cli/getHexagonEdgeLengthAvgKm.txt @@ -0,0 +1,2 @@ +add_h3_cli_test(testCliGetHexagonEdgeLengthAvgKm "getHexagonEdgeLengthAvgKm -r 0" "1281.2560110000") +add_h3_cli_test(testCliDontGetHexagonEdgeLengthAvgKm "getHexagonEdgeLengthAvgKm -r 20 2>&1" "Error 4: Resolution argument was outside of acceptable range") diff --git a/tests/cli/getHexagonEdgeLengthAvgM.txt b/tests/cli/getHexagonEdgeLengthAvgM.txt new file mode 100644 index 000000000..022103101 --- /dev/null +++ b/tests/cli/getHexagonEdgeLengthAvgM.txt @@ -0,0 +1,2 @@ +add_h3_cli_test(testCliGetHexagonEdgeLengthAvgM "getHexagonEdgeLengthAvgM -r 0" "1281256.0109999999") +add_h3_cli_test(testCliDontGetHexagonEdgeLengthAvgM "getHexagonEdgeLengthAvgM -r 20 2>&1" "Error 4: Resolution argument was outside of acceptable range") diff --git a/tests/cli/getNumCells.txt b/tests/cli/getNumCells.txt new file mode 100644 index 000000000..de5e0cdda --- /dev/null +++ b/tests/cli/getNumCells.txt @@ -0,0 +1,2 @@ +add_h3_cli_test(testCliGetNumCells "getNumCells -r 0" "122") +add_h3_cli_test(testCliDontGetNumCells "getNumCells -r 20 2>&1" "Error 4: Resolution argument was outside of acceptable range") diff --git a/tests/cli/getPentagons.txt b/tests/cli/getPentagons.txt new file mode 100644 index 000000000..60f3abe41 --- /dev/null +++ b/tests/cli/getPentagons.txt @@ -0,0 +1,2 @@ +add_h3_cli_test(testCliGetPentagons "getPentagons -r 0" "[8009fffffffffff, 801dfffffffffff, 8031fffffffffff, 804dfffffffffff, 8063fffffffffff, 8075fffffffffff, 807ffffffffffff, 8091fffffffffff, 80a7fffffffffff, 80c3fffffffffff, 80d7fffffffffff, 80ebfffffffffff]") +add_h3_cli_test(testCliDontGetPentagons "getPentagons -r 20 2>&1" "Error 4: Resolution argument was outside of acceptable range") diff --git a/tests/cli/getRes0Cells.txt b/tests/cli/getRes0Cells.txt new file mode 100644 index 000000000..437c9fc1a --- /dev/null +++ b/tests/cli/getRes0Cells.txt @@ -0,0 +1 @@ +add_h3_cli_test(testCliGetRes0Cells "getRes0Cells" "[8001fffffffffff, 8003fffffffffff, 8005fffffffffff, 8007fffffffffff, 8009fffffffffff, 800bfffffffffff, 800dfffffffffff, 800ffffffffffff, 8011fffffffffff, 8013fffffffffff, 8015fffffffffff, 8017fffffffffff, 8019fffffffffff, 801bfffffffffff, 801dfffffffffff, 801ffffffffffff, 8021fffffffffff, 8023fffffffffff, 8025fffffffffff, 8027fffffffffff, 8029fffffffffff, 802bfffffffffff, 802dfffffffffff, 802ffffffffffff, 8031fffffffffff, 8033fffffffffff, 8035fffffffffff, 8037fffffffffff, 8039fffffffffff, 803bfffffffffff, 803dfffffffffff, 803ffffffffffff, 8041fffffffffff, 8043fffffffffff, 8045fffffffffff, 8047fffffffffff, 8049fffffffffff, 804bfffffffffff, 804dfffffffffff, 804ffffffffffff, 8051fffffffffff, 8053fffffffffff, 8055fffffffffff, 8057fffffffffff, 8059fffffffffff, 805bfffffffffff, 805dfffffffffff, 805ffffffffffff, 8061fffffffffff, 8063fffffffffff, 8065fffffffffff, 8067fffffffffff, 8069fffffffffff, 806bfffffffffff, 806dfffffffffff, 806ffffffffffff, 8071fffffffffff, 8073fffffffffff, 8075fffffffffff, 8077fffffffffff, 8079fffffffffff, 807bfffffffffff, 807dfffffffffff, 807ffffffffffff, 8081fffffffffff, 8083fffffffffff, 8085fffffffffff, 8087fffffffffff, 8089fffffffffff, 808bfffffffffff, 808dfffffffffff, 808ffffffffffff, 8091fffffffffff, 8093fffffffffff, 8095fffffffffff, 8097fffffffffff, 8099fffffffffff, 809bfffffffffff, 809dfffffffffff, 809ffffffffffff, 80a1fffffffffff, 80a3fffffffffff, 80a5fffffffffff, 80a7fffffffffff, 80a9fffffffffff, 80abfffffffffff, 80adfffffffffff, 80affffffffffff, 80b1fffffffffff, 80b3fffffffffff, 80b5fffffffffff, 80b7fffffffffff, 80b9fffffffffff, 80bbfffffffffff, 80bdfffffffffff, 80bffffffffffff, 80c1fffffffffff, 80c3fffffffffff, 80c5fffffffffff, 80c7fffffffffff, 80c9fffffffffff, 80cbfffffffffff, 80cdfffffffffff, 80cffffffffffff, 80d1fffffffffff, 80d3fffffffffff, 80d5fffffffffff, 80d7fffffffffff, 80d9fffffffffff, 80dbfffffffffff, 80ddfffffffffff, 80dffffffffffff, 80e1fffffffffff, 80e3fffffffffff, 80e5fffffffffff, 80e7fffffffffff, 80e9fffffffffff, 80ebfffffffffff, 80edfffffffffff, 80effffffffffff, 80f1fffffffffff, 80f3fffffffffff]") diff --git a/tests/cli/greatCircleDistanceKm.txt b/tests/cli/greatCircleDistanceKm.txt new file mode 100644 index 000000000..b75391b1f --- /dev/null +++ b/tests/cli/greatCircleDistanceKm.txt @@ -0,0 +1,4 @@ +add_h3_cli_test(testCliGreatCircleDistanceKmArg "greatCircleDistanceKm -c '[[0, 1], [1, 2]]'" "157.2495585118") +add_h3_cli_test(testCliGreatCircleDistanceKmFile "greatCircleDistanceKm -f ${PROJECT_SOURCE_DIR}/tests/inputfiles/great_circle_distance.txt" "157.2495585118") +add_h3_cli_test(testCliGreatCircleDistanceKmStdin "greatCircleDistanceKm -f -- < ${PROJECT_SOURCE_DIR}/tests/inputfiles/great_circle_distance.txt" "157.2495585118") +add_h3_cli_test(testCliGreatCircleDistanceKmBadArg "greatCircleDistanceKm -c '[[0, 1]]' 2>&1" "Only two pairs of coordinates should be provided.") diff --git a/tests/cli/greatCircleDistanceM.txt b/tests/cli/greatCircleDistanceM.txt new file mode 100644 index 000000000..2e0bbfea5 --- /dev/null +++ b/tests/cli/greatCircleDistanceM.txt @@ -0,0 +1,4 @@ +add_h3_cli_test(testCliGreatCircleDistanceMArg "greatCircleDistanceM -c '[[0, 1], [1, 2]]'" "157249.5585117787") +add_h3_cli_test(testCliGreatCircleDistanceMFile "greatCircleDistanceM -f ${PROJECT_SOURCE_DIR}/tests/inputfiles/great_circle_distance.txt" "157249.5585117787") +add_h3_cli_test(testCliGreatCircleDistanceMStdin "greatCircleDistanceM -f -- < ${PROJECT_SOURCE_DIR}/tests/inputfiles/great_circle_distance.txt" "157249.5585117787") +add_h3_cli_test(testCliGreatCircleDistanceMBadArg "greatCircleDistanceM -c '[[0, 1]]' 2>&1" "Only two pairs of coordinates should be provided.") 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.") diff --git a/tests/cli/isValidDirectedEdge.txt b/tests/cli/isValidDirectedEdge.txt new file mode 100644 index 000000000..76fdaee9f --- /dev/null +++ b/tests/cli/isValidDirectedEdge.txt @@ -0,0 +1,2 @@ +add_h3_cli_test(testCliIsValidDirectedEdge "isValidDirectedEdge -c 115283473fffffff" "true") +add_h3_cli_test(testCliIsNotValidDirectedEdge "isValidDirectedEdge -c 85283473fffffff" "false") diff --git a/tests/cli/isValidVertex.txt b/tests/cli/isValidVertex.txt new file mode 100644 index 000000000..d52d98a89 --- /dev/null +++ b/tests/cli/isValidVertex.txt @@ -0,0 +1,2 @@ +add_h3_cli_test(testCliIsValidVertex "isValidVertex -c 22528340bfffffff" "true") +add_h3_cli_test(testCliIsNotValidVertex "isValidVertex -c 85283473fffffff" "false") diff --git a/tests/cli/originToDirectedEdges.txt b/tests/cli/originToDirectedEdges.txt new file mode 100644 index 000000000..8c7c95e4b --- /dev/null +++ b/tests/cli/originToDirectedEdges.txt @@ -0,0 +1,2 @@ +add_h3_cli_test(testCliOriginToDirectedEdges "originToDirectedEdges -c 85283473fffffff" "[115283473fffffff, 125283473fffffff, 135283473fffffff, 145283473fffffff, 155283473fffffff, 165283473fffffff]") +add_h3_cli_test(testCliNotOriginToDirectedEdges "originToDirectedEdges -c 115283473fffffff 2>&1" "Error 5: Cell argument was not valid") diff --git a/tests/cli/pentagonCount.txt b/tests/cli/pentagonCount.txt new file mode 100644 index 000000000..bc79f391a --- /dev/null +++ b/tests/cli/pentagonCount.txt @@ -0,0 +1 @@ +add_h3_cli_test(testCliPentagonCount "pentagonCount" "12") diff --git a/tests/cli/radsToDegs.txt b/tests/cli/radsToDegs.txt new file mode 100644 index 000000000..d864100e6 --- /dev/null +++ b/tests/cli/radsToDegs.txt @@ -0,0 +1 @@ +add_h3_cli_test(testCliRadsToDegs "radsToDegs -r 3.1415926536" "180.0000000006") diff --git a/tests/cli/vertexToLatLng.txt b/tests/cli/vertexToLatLng.txt new file mode 100644 index 000000000..7204b3d1c --- /dev/null +++ b/tests/cli/vertexToLatLng.txt @@ -0,0 +1,2 @@ +add_h3_cli_test(testCliVertexToLatLng "vertexToLatLng -c 22528340bfffffff" "POINT(-121.9150803271 37.2713558667)") +add_h3_cli_test(testCliNotVertexToLatLng "vertexToLatLng -c 85283473fffffff 2>&1" "Error 8: Vertex argument was not valid") diff --git a/tests/inputfiles/great_circle_distance.txt b/tests/inputfiles/great_circle_distance.txt new file mode 100644 index 000000000..0b812a23d --- /dev/null +++ b/tests/inputfiles/great_circle_distance.txt @@ -0,0 +1 @@ +[[0, 1], [1, 2]]