diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index f482aed..2c72797 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,5 +1,5 @@ { - "name": "GitHub Codespaces", + "name": "libgeohex", "customizations": { "vscode": { "extensions": [ @@ -13,5 +13,6 @@ } }, "dockerComposeFile": "./../compose.yaml", - "service": "shell" + "service": "shell", + "workspaceFolder": "/workspaces/libgeohex" } diff --git a/.devcontainer/local/devcontainer.json b/.devcontainer/local/devcontainer.json deleted file mode 100644 index c0d5dfd..0000000 --- a/.devcontainer/local/devcontainer.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "Local VSCode", - "customizations": { - "vscode": { - "extensions": [ - "ms-vscode.cpptools", - "ms-vscode.cpptools-extension-pack", - "ms-vscode.cmake-tools", - "ms-azuretools.vscode-docker", - "editorconfig.editorconfig", - "markis.code-coverage" - ] - } - }, - "dockerComposeFile": "./../../compose.yaml", - "service": "shell", - "mounts": [ - "source=${localWorkspaceFolder},target=/workspaces/libgeohex,type=bind,consistency=cached" - ], - "workspaceFolder": "/workspaces/libgeohex" -} diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index eea5784..5ada1d6 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -6,32 +6,100 @@ on: pull_request: jobs: Linux: - runs-on: ubuntu-latest + name: Linux (${{ matrix.display_platform }}) + runs-on: ${{ matrix.runner }} strategy: + fail-fast: false matrix: - platform: ['linux/amd64', 'linux/arm64/v8', 'linux/s390x', 'linux/arm/v7'] + include: + - display_platform: linux/amd64 + platform: linux/amd64 + runner: ubuntu-24.04 + native_platform: linux/amd64 + qemu_platforms: "" + run_sanitizers: "true" + - display_platform: linux/arm64 + platform: linux/arm64 + runner: ubuntu-24.04-arm + native_platform: linux/arm64 + qemu_platforms: "" + run_sanitizers: "true" + - display_platform: linux/s390x + platform: linux/s390x + runner: ubuntu-24.04 + native_platform: linux/amd64 + qemu_platforms: s390x + run_sanitizers: "false" + - display_platform: linux/arm/v7 + platform: linux/arm/v7 + runner: ubuntu-24.04 + native_platform: linux/amd64 + qemu_platforms: arm + run_sanitizers: "false" + - display_platform: linux/i386 + platform: linux/386 + runner: ubuntu-24.04 + native_platform: linux/amd64 + qemu_platforms: "386" + run_sanitizers: "false" steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: submodules: true - name: Setup QEMU - uses: docker/setup-qemu-action@v3 + if: matrix.qemu_platforms != '' + uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0 with: - platforms: "arm64,s390x,arm" + platforms: ${{ matrix.qemu_platforms }} - name: Setup buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 - name: Build container run: | - docker build --pull --no-cache --build-arg PLATFORM="${{ matrix.platform }}" --tag "test" . + docker buildx build \ + --pull \ + --no-cache \ + --load \ + --platform "${{ matrix.platform }}" \ + --build-arg PLATFORM="${{ matrix.platform }}" \ + --tag "test" \ + . - name: Test run: | docker run \ + --platform "${{ matrix.platform }}" \ --privileged \ --cap-add SYS_ADMIN \ --security-opt seccomp:unconfined \ - -e NATIVE_PLATFORM="linux/amd64" \ + -e NATIVE_PLATFORM="${{ matrix.native_platform }}" \ + -e RUN_SANITIZERS="${{ matrix.run_sanitizers }}" \ -v "$(pwd):/workspaces/libgeohex" \ -w "/workspaces/libgeohex" \ -i "test" \ ./ci.sh + macOS: + runs-on: macos-latest + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + fetch-depth: 1 + - name: Configure + run: cmake -S . -B build -DBUILD_TESTS=ON + - name: Build + run: cmake --build build --parallel + - name: Test + run: ctest --test-dir build --output-on-failure + Windows: + runs-on: windows-latest + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + fetch-depth: 1 + - name: Configure + run: cmake -S . -B build -DBUILD_TESTS=ON + - name: Build + run: cmake --build build --config Debug --parallel + - name: Test + run: ctest --test-dir build --build-config Debug --output-on-failure diff --git a/CMakeLists.txt b/CMakeLists.txt index 7e77915..af14ec9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.10) -project(libgeohex VERSION 1.1.1 LANGUAGES C) +project(libgeohex VERSION 2.0.0 LANGUAGES C) set(CMAKE_C_STANDARD 99) set(CMAKE_C_STANDARD_REQUIRED ON) @@ -15,6 +15,15 @@ option(BUILD_STATIC_LIBS "Build static libraries" ON) option(BUILD_SHARED_LIBS "Build shared libraries" ON) set(GEOHEX_TARGETS) +set(GEOHEX_MATH_LIBRARIES) + +if(NOT WIN32) + list(APPEND GEOHEX_MATH_LIBRARIES m) +endif() + +if(WIN32) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") +endif() if (BUILD_STATIC_LIBS) add_library(geohex_static STATIC @@ -28,7 +37,10 @@ if (BUILD_STATIC_LIBS) $ ) - target_link_libraries(geohex_static PUBLIC m) + target_compile_definitions(geohex_static PUBLIC GEOHEX_STATIC_DEFINE) + if(GEOHEX_MATH_LIBRARIES) + target_link_libraries(geohex_static PUBLIC ${GEOHEX_MATH_LIBRARIES}) + endif() list(APPEND GEOHEX_TARGETS geohex_static) endif() @@ -39,13 +51,19 @@ if(BUILD_SHARED_LIBS) ) set_target_properties(geohex_shared PROPERTIES OUTPUT_NAME geohex) + if(WIN32) + set_target_properties(geohex_shared PROPERTIES ARCHIVE_OUTPUT_NAME geohex_shared) + endif() target_include_directories(geohex_shared PUBLIC $ $ ) - target_link_libraries(geohex_shared PUBLIC m) + target_compile_definitions(geohex_shared PRIVATE GEOHEX_BUILDING_LIBRARY) + if(GEOHEX_MATH_LIBRARIES) + target_link_libraries(geohex_shared PUBLIC ${GEOHEX_MATH_LIBRARIES}) + endif() list(APPEND GEOHEX_TARGETS geohex_shared) endif() diff --git a/Dockerfile b/Dockerfile index 0776c2b..2237bac 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ ARG PLATFORM=${BUILDPLATFORM:-linux/amd64} -FROM --platform=${PLATFORM} debian:bookworm +FROM --platform=${PLATFORM} debian:trixie ARG PLATFORM diff --git a/LICENSE b/LICENSE index 85cbf77..c786b5b 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2024 Go Kudo +Copyright (c) 2024-2026 Go Kudo Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/ci.sh b/ci.sh index 5e1c657..66dc8ed 100755 --- a/ci.sh +++ b/ci.sh @@ -18,15 +18,31 @@ build_and_test() { rm -rf "build" } +should_run_sanitizers() { + if test "x${RUN_SANITIZERS}" = "xtrue"; then + return 0 + fi + + if test "x${RUN_SANITIZERS}" = "xfalse"; then + return 1 + fi + + if test "x${NATIVE_PLATFORM}" = "x"; then + return 0 + fi + + test "x${PLATFORM}" != "xlinux/s390x" && test "x${PLATFORM}" = "x${NATIVE_PLATFORM}" +} + build_and_test "clang" false false false -if test "x${NATIVE_PLATFORM}" = "x" || (test "x${PLATFORM}" != "xlinux/s390x" && test "x${PLATFORM}" = "x${NATIVE_PLATFORM}"); then +if should_run_sanitizers; then build_and_test "clang" true false false build_and_test "clang" false true false build_and_test "clang" false false true fi build_and_test "gcc" false false false -if test "x${NATIVE_PLATFORM}" = "x" || (test "x${PLATFORM}" != "xlinux/s390x" && test "x${PLATFORM}" = "x${NATIVE_PLATFORM}"); then +if should_run_sanitizers; then build_and_test "gcc" true false false build_and_test "gcc" false true false fi diff --git a/include/geohex/compat.h b/include/geohex/compat.h new file mode 100644 index 0000000..3654a28 --- /dev/null +++ b/include/geohex/compat.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: MIT */ +/* + * libgeohex + * + * Copyright (c) 2024-2026 Go Kudo Kudo (https://github.com/zeriyoshi) + * + * GeoHex original implementation by @sa2da (http://twitter.com/sa2da) + * https://www.geohex.org/ + * + * Released under the MIT license. + * see https://opensource.org/licenses/MIT + */ +#ifndef GEOHEX_COMPAT_H +#define GEOHEX_COMPAT_H + +#if defined(_WIN32) || defined(__CYGWIN__) +# if defined(GEOHEX_STATIC_DEFINE) +# define GEOHEX_API +# elif defined(GEOHEX_BUILDING_LIBRARY) +# define GEOHEX_API __declspec(dllexport) +# else +# define GEOHEX_API __declspec(dllimport) +# endif +#elif defined(__GNUC__) && __GNUC__ >= 4 +# define GEOHEX_API __attribute__((visibility("default"))) +#else +# define GEOHEX_API +#endif + +#define GEOHEX_PI 3.14159265358979323846 + +#endif /* GEOHEX_COMPAT_H */ diff --git a/include/geohex/geohex.h b/include/geohex/geohex.h index d89aa5b..9004dab 100644 --- a/include/geohex/geohex.h +++ b/include/geohex/geohex.h @@ -2,7 +2,7 @@ /* * libgeohex * - * Copyright (c) 2024 Go Kudo (https://github.com/zeriyoshi) + * Copyright (c) 2024-2026 Go Kudo Kudo (https://github.com/zeriyoshi) * * GeoHex original implementation by @sa2da (http://twitter.com/sa2da) * https://www.geohex.org/ @@ -16,11 +16,13 @@ #include #include +#include "geohex/compat.h" + #ifdef __cplusplus extern "C" { #endif -#define LIBGEOHEX_VERSION "1.1.1" +#define LIBGEOHEX_VERSION "2.0.0" #define GEOHEX_COMPLIANT_VERSION "3.2" #define MAX_LEVEL 15 @@ -47,12 +49,12 @@ typedef struct { geohex_code_t code; } zone_t; -bool adjust_xy(int32_t x, int32_t y, uint32_t level, xy_t *out); -bool get_xy_by_location(const loc_t *location, uint32_t level, xy_t *out); -bool get_xy_by_code(const geohex_code_t code, xy_t *out); -bool get_zone_by_location(const loc_t *location, uint32_t level, zone_t *out); -bool get_zone_by_code(const geohex_code_t code, zone_t *out); -bool get_zone_by_xy(const xy_t *xy, uint32_t level, zone_t *out); +GEOHEX_API bool adjust_xy(int32_t x, int32_t y, uint32_t level, xy_t *out); +GEOHEX_API bool get_xy_by_location(const loc_t *location, uint32_t level, xy_t *out); +GEOHEX_API bool get_xy_by_code(const geohex_code_t code, xy_t *out); +GEOHEX_API bool get_zone_by_location(const loc_t *location, uint32_t level, zone_t *out); +GEOHEX_API bool get_zone_by_code(const geohex_code_t code, zone_t *out); +GEOHEX_API bool get_zone_by_xy(const xy_t *xy, uint32_t level, zone_t *out); #ifdef __cplusplus } diff --git a/src/geohex.c b/src/geohex.c index c2b452b..2323827 100644 --- a/src/geohex.c +++ b/src/geohex.c @@ -2,7 +2,7 @@ /* * libgeohex * - * Copyright (c) 2024 Go Kudo (https://github.com/zeriyoshi) + * Copyright (c) 2024-2026 Go Kudo Kudo (https://github.com/zeriyoshi) * * GeoHex original implementation by @sa2da (http://twitter.com/sa2da) * https://www.geohex.org/ @@ -21,7 +21,7 @@ #define GEOHEX_KEY "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" #define H_BASE 20037508.34 -#define H_K 0.5773502691896257 /* tan(M_PI / 6.0) */ +#define H_K 0.5773502691896257 /* tan(GEOHEX_PI / 6.0) */ const uint32_t pow3_table[] = { 1, /* pow(3, 0) */ @@ -57,55 +57,59 @@ static inline int char_to_index(char c) { } } -double calc_hex_size(uint32_t level) { +GEOHEX_API double calc_hex_size(uint32_t level) { return H_BASE / pow3_table[level + 3]; } -void loc2xy(double lon, double lat, double *dx, double *dy) { +GEOHEX_API void loc2xy(double lon, double lat, double *dx, double *dy) { *dx = lon * H_BASE / 180.0; - *dy = log(tan((90.0 + lat) * M_PI / 360.0)) * (H_BASE / M_PI); + *dy = log(tan((90.0 + lat) * GEOHEX_PI / 360.0)) * (H_BASE / GEOHEX_PI); } -void xy2loc(double dx, double dy, double *lon, double *lat) { +GEOHEX_API void xy2loc(double dx, double dy, double *lon, double *lat) { + double lat_rad; + *lon = (dx / H_BASE) * 180.0; - double lat_rad = (dy / H_BASE) * M_PI; - *lat = (2.0 * atan(exp(lat_rad)) - M_PI / 2.0) * 180.0 / M_PI; + lat_rad = (dy / H_BASE) * GEOHEX_PI; + *lat = (2.0 * atan(exp(lat_rad)) - GEOHEX_PI / 2.0) * 180.0 / GEOHEX_PI; } +GEOHEX_API bool adjust_xy(int32_t x, int32_t y, uint32_t level, xy_t *out) { + int32_t tmp, max_hsteps, hsteps, dif, dif_x, dif_y, edge_x, edge_y; + bool rev; -bool adjust_xy(int32_t x, int32_t y, uint32_t level, xy_t *out) { if (!out) { return false; } - int32_t max_hsteps = pow3_table[level + 2]; - int32_t hsteps = abs(x - y); - bool rev = false; + max_hsteps = pow3_table[level + 2]; + hsteps = abs(x - y); + rev = false; if (hsteps == max_hsteps && x > y) { - int32_t tmp = x; + tmp = x; x = y; y = tmp; rev = true; } else if (hsteps > max_hsteps) { - int32_t dif = hsteps - max_hsteps; - int32_t dif_x = dif / 2; - int32_t dif_y = dif - dif_x; + dif = hsteps - max_hsteps; + dif_x = dif / 2; + dif_y = dif - dif_x; if (x > y) { - int32_t edge_x = x - dif_x; - int32_t edge_y = y + dif_y; - int32_t temp = edge_x; + edge_x = x - dif_x; + edge_y = y + dif_y; + tmp = edge_x; edge_x = edge_y; - edge_y = temp; + edge_y = tmp; x = edge_x + dif_x; y = edge_y - dif_y; } else if (y > x) { - int32_t edge_x = x + dif_x; - int32_t edge_y = y - dif_y; - int32_t temp = edge_x; + edge_x = x + dif_x; + edge_y = y - dif_y; + tmp = edge_x; edge_x = edge_y; - edge_y = temp; + edge_y = tmp; x = edge_x - dif_x; y = edge_y + dif_y; } @@ -114,29 +118,33 @@ bool adjust_xy(int32_t x, int32_t y, uint32_t level, xy_t *out) { out->x = x; out->y = y; out->rev = rev; + return true; } -bool get_xy_by_location(const loc_t *location, uint32_t level, xy_t *out) { +GEOHEX_API bool get_xy_by_location(const loc_t *location, uint32_t level, xy_t *out) { + int32_t h_x, h_y; + double h_size, lon_grid, lat_grid, unit_x, unit_y, h_pos_x, h_pos_y, + h_x_q, h_y_q; + if (!location || !out) { return false; } - double h_size = calc_hex_size(level); - double lon_grid, lat_grid; + h_size = calc_hex_size(level); loc2xy(location->lon, location->lat, &lon_grid, &lat_grid); - double unit_x = 6.0 * h_size; - double unit_y = 6.0 * h_size * H_K; + unit_x = 6.0 * h_size; + unit_y = 6.0 * h_size * H_K; - double h_pos_x = (lon_grid + lat_grid / H_K) / unit_x; - double h_pos_y = (lat_grid - H_K * lon_grid) / unit_y; + h_pos_x = (lon_grid + lat_grid / H_K) / unit_x; + h_pos_y = (lat_grid - H_K * lon_grid) / unit_y; - int32_t h_x = (int32_t) round(h_pos_x); - int32_t h_y = (int32_t) round(h_pos_y); + h_x = (int32_t) round(h_pos_x); + h_y = (int32_t) round(h_pos_y); - double h_x_q = h_pos_x - floor(h_pos_x); - double h_y_q = h_pos_y - floor(h_pos_y); + h_x_q = h_pos_x - floor(h_pos_x); + h_y_q = h_pos_y - floor(h_pos_y); if (h_y_q > -h_x_q + 1) { if (h_y_q < 2 * h_x_q && h_y_q > 0.5 * h_x_q) { @@ -153,25 +161,31 @@ bool get_xy_by_location(const loc_t *location, uint32_t level, xy_t *out) { return adjust_xy(h_x, h_y, level, out); } -bool get_xy_by_code(const geohex_code_t code, xy_t *out) { +GEOHEX_API bool get_xy_by_code(const geohex_code_t code, xy_t *out) { + uint32_t code_len, level; + int32_t i, h_x, h_y, c1_idx, c2_idx, code3, d9xlen, target_len, + h_decx[MAX_H_DEC3_LEN] = {0}, h_decy[MAX_H_DEC3_LEN] = {0}, + digit, h_pow; + char code3_str[5], h_dec9[MAX_H_DEC9_LEN] = {0}; + if (!out) { return false; } - uint32_t code_len = strlen(code); - uint32_t level = code_len - 2; - int32_t h_x = 0, h_y = 0; + code_len = strlen(code); + level = code_len - 2; + h_x = 0; + h_y = 0; - int32_t c1_idx = char_to_index(code[0]); - int32_t c2_idx = char_to_index(code[1]); + c1_idx = char_to_index(code[0]); + c2_idx = char_to_index(code[1]); if (c1_idx == -1 || c2_idx == -1) { return false; } - int32_t code3 = c1_idx * 30 + c2_idx; + code3 = c1_idx * 30 + c2_idx; - char code3_str[5]; snprintf(code3_str, sizeof(code3_str), "%d", code3); if ((code3_str[0] == '1' || code3_str[0] == '5') && @@ -180,27 +194,24 @@ bool get_xy_by_code(const geohex_code_t code, xy_t *out) { code3_str[0] = (code3_str[0] == '5') ? '7' : '3'; } - char h_dec9[MAX_H_DEC9_LEN] = {0}; snprintf(h_dec9, sizeof(h_dec9), "%s%s", code3_str, code + 2); - int32_t d9xlen = strlen(h_dec9); - int32_t target_len = level + 3; + d9xlen = strlen(h_dec9); + target_len = level + 3; if (d9xlen < target_len) { memmove(h_dec9 + (target_len - d9xlen), h_dec9, d9xlen + 1); memset(h_dec9, '0', target_len - d9xlen); d9xlen = target_len; } - int32_t h_decx[MAX_H_DEC3_LEN] = {0}; - int32_t h_decy[MAX_H_DEC3_LEN] = {0}; - for (int32_t i = 0; i < d9xlen; i++) { - int32_t digit = h_dec9[i] - '0'; + for (i = 0; i < d9xlen; i++) { + digit = h_dec9[i] - '0'; h_decx[i] = digit / 3; h_decy[i] = digit % 3; } - for (int32_t i = 0; i <= (int32_t)(level + 2); i++) { - int32_t h_pow = pow3_table[level + 2 - i]; + for (i = 0; i <= (int32_t)(level + 2); i++) { + h_pow = pow3_table[level + 2 - i]; if (h_decx[i] == 0) { h_x -= h_pow; @@ -218,13 +229,13 @@ bool get_xy_by_code(const geohex_code_t code, xy_t *out) { return adjust_xy(h_x, h_y, level, out); } -bool get_zone_by_location(const loc_t *location, uint32_t level, zone_t *out) { +GEOHEX_API bool get_zone_by_location(const loc_t *location, uint32_t level, zone_t *out) { + xy_t xy; + if (!out) { return false; } - xy_t xy; - if (!get_xy_by_location(location, level, &xy)) { return false; } @@ -232,53 +243,61 @@ bool get_zone_by_location(const loc_t *location, uint32_t level, zone_t *out) { return get_zone_by_xy(&xy, level, out); } -bool get_zone_by_code(const geohex_code_t code, zone_t *out) { +GEOHEX_API bool get_zone_by_code(const geohex_code_t code, zone_t *out) { + xy_t xy; + if (!out) { return false; } - xy_t xy; - if (!get_xy_by_code(code, &xy)) { return false; } - uint32_t level = strlen(code) - 2; - - return get_zone_by_xy(&xy, level, out); + return get_zone_by_xy(&xy, (strlen(code) - 2), out); } -bool get_zone_by_xy(const xy_t *xy, uint32_t level, zone_t *out) { +GEOHEX_API bool get_zone_by_xy(const xy_t *xy, uint32_t level, zone_t *out) { + uint32_t i; + int32_t tmp, h_x, h_y, max_hsteps, + code3_x[MAX_CODE_LEN + 2], code3_y[MAX_CODE_LEN + 2], + h_code_digits[MAX_CODE_LEN + 2], + mod_x, mod_y, h_1_int, h_a1, h_a2, + h_pow, half_h_pow; + double h_size, unit_x, unit_y, h_lat, h_lon, z_loc_x, z_loc_y; + if (!xy || !out) { return false; } - double h_size = calc_hex_size(level); - int32_t h_x = xy->x, h_y = xy->y; + h_size = calc_hex_size(level); + h_x = xy->x; + h_y = xy->y; - double unit_x = 6.0 * h_size; - double unit_y = 6.0 * h_size * H_K; + unit_x = 6.0 * h_size; + unit_y = 6.0 * h_size * H_K; - double h_lat = (H_K * h_x * unit_x + h_y * unit_y) / 2.0; - double h_lon = (h_lat - h_y * unit_y) / H_K; + h_lat = (H_K * h_x * unit_x + h_y * unit_y) / 2.0; + h_lon = (h_lat - h_y * unit_y) / H_K; - double z_loc_x, z_loc_y; + z_loc_x = 0.0; + z_loc_y = 0.0; xy2loc(h_lon, h_lat, &z_loc_x, &z_loc_y); - int32_t max_hsteps = pow3_table[level + 2]; + max_hsteps = pow3_table[level + 2]; if (abs(h_x - h_y) == max_hsteps && h_x > h_y) { - int32_t tmp = h_x; + tmp = h_x; h_x = h_y; h_y = tmp; z_loc_x = -180.0; } - int32_t code3_x[MAX_CODE_LEN + 2], code3_y[MAX_CODE_LEN + 2]; - int32_t mod_x = h_x, mod_y = h_y; + mod_x = h_x; + mod_y = h_y; - for (int32_t i = 0; i <= level + 2; i++) { - int32_t h_pow = pow3_table[level + 2 - i]; - int32_t half_h_pow = (h_pow + 1) / 2; + for (i = 0; i <= level + 2; i++) { + h_pow = pow3_table[level + 2 - i]; + half_h_pow = (h_pow + 1) / 2; if (mod_x >= half_h_pow) { code3_x[i] = 2; @@ -302,30 +321,31 @@ bool get_zone_by_xy(const xy_t *xy, uint32_t level, zone_t *out) { if (i == 2 && (z_loc_x == -180.0 || z_loc_x >= 0.0)) { if (code3_x[0] == 2 && code3_y[0] == 1 && - code3_x[1] == code3_y[1] && code3_x[2] == code3_y[2]) { + code3_x[1] == code3_y[1] && code3_x[2] == code3_y[2] + ) { code3_x[0] = 1; code3_y[0] = 2; } else if (code3_x[0] == 1 && code3_y[0] == 0 && - code3_x[1] == code3_y[1] && code3_x[2] == code3_y[2]) { + code3_x[1] == code3_y[1] && code3_x[2] == code3_y[2] + ) { code3_x[0] = 0; code3_y[0] = 1; } } } - int32_t h_code_digits[MAX_CODE_LEN + 2]; - for (int32_t i = 0; i <= level + 2; i++) { + for (i = 0; i <= level + 2; i++) { h_code_digits[i] = code3_x[i] * 3 + code3_y[i]; } - int32_t h_1_int = h_code_digits[0] * 100 + h_code_digits[1] * 10 + h_code_digits[2]; - int32_t h_a1 = h_1_int / 30; - int32_t h_a2 = h_1_int % 30; + h_1_int = h_code_digits[0] * 100 + h_code_digits[1] * 10 + h_code_digits[2]; + h_a1 = h_1_int / 30; + h_a2 = h_1_int % 30; out->code[0] = GEOHEX_KEY[h_a1]; out->code[1] = GEOHEX_KEY[h_a2]; - for (int32_t i = 3; i <= level + 2; i++) { + for (i = 3; i <= level + 2; i++) { out->code[i - 1] = '0' + h_code_digits[i]; } out->code[level + 2] = '\0'; diff --git a/tests/geohex_private.h b/tests/geohex_private.h index aa44f75..1e6d49d 100644 --- a/tests/geohex_private.h +++ b/tests/geohex_private.h @@ -2,7 +2,7 @@ /* * libgeohex * - * Copyright (c) 2024 Go Kudo (https://github.com/zeriyoshi) + * Copyright (c) 2024-2026 Go Kudo Kudo (https://github.com/zeriyoshi) * * GeoHex original implementation by @sa2da (http://twitter.com/sa2da) * https://www.geohex.org/ @@ -15,8 +15,10 @@ #include -double calc_hex_size(uint32_t level); -void loc2xy(double lon, double lat, double *dx, double *dy); -void xy2loc(double dx, double dy, double *lon, double *lat); +#include "geohex/compat.h" + +GEOHEX_API double calc_hex_size(uint32_t level); +GEOHEX_API void loc2xy(double lon, double lat, double *dx, double *dy); +GEOHEX_API void xy2loc(double dx, double dy, double *lon, double *lat); #endif /* GEOHEX_PRIVATE_H */ diff --git a/tests/json_data.h b/tests/json_data.h index e046c05..969daad 100644 --- a/tests/json_data.h +++ b/tests/json_data.h @@ -2,7 +2,7 @@ /* * libgeohex * - * Copyright (c) 2024 Go Kudo (https://github.com/zeriyoshi) + * Copyright (c) 2024-2026 Go Kudo Kudo (https://github.com/zeriyoshi) * * GeoHex original implementation by @sa2da (http://twitter.com/sa2da) * https://www.geohex.org/ diff --git a/tests/test_geohex.c b/tests/test_geohex.c index e438caf..64e32e9 100644 --- a/tests/test_geohex.c +++ b/tests/test_geohex.c @@ -2,7 +2,7 @@ /* * libgeohex * - * Copyright (c) 2024 Go Kudo (https://github.com/zeriyoshi) + * Copyright (c) 2024-2026 Go Kudo Kudo (https://github.com/zeriyoshi) * * GeoHex original implementation by @sa2da (http://twitter.com/sa2da) * https://www.geohex.org/ @@ -75,12 +75,11 @@ void test_adjust_xy(void) void test_get_xy_by_location(void) { xy_t out; + loc_t loc; for (uint32_t i = 0; i < (sizeof(coord2xy_data) / sizeof(coord2xy_data[0])); i++) { - loc_t loc = { - .lat = coord2xy_data[i].lat, - .lon = coord2xy_data[i].lon, - }; + loc.lat = coord2xy_data[i].lat; + loc.lon = coord2xy_data[i].lon; TEST_ASSERT_TRUE(get_xy_by_location(&loc, coord2xy_data[i].level, &out)); TEST_ASSERT_DOUBLE_WITHIN(15, coord2xy_data[i].x, out.x); @@ -91,13 +90,12 @@ void test_get_xy_by_location(void) void test_get_zone_by_xy(void) { zone_t out; + xy_t xy; for (uint32_t i = 0; i < (sizeof(xy2hex_data) / sizeof(xy2hex_data[0])); i++) { - xy_t xy = { - .x = xy2hex_data[i].x, - .y = xy2hex_data[i].y, - .rev = false, - }; + xy.x = xy2hex_data[i].x; + xy.y = xy2hex_data[i].y; + xy.rev = false; TEST_ASSERT_TRUE(get_zone_by_xy(&xy, xy2hex_data[i].level, &out)); TEST_ASSERT_EQUAL_STRING(xy2hex_data[i].code, out.code); @@ -107,8 +105,9 @@ void test_get_zone_by_xy(void) void test_get_xy_by_code(void) { xy_t out; + uint32_t i; - for (uint32_t i = 0; i < (sizeof(code2xy_data) / sizeof(code2xy_data[0])); i++) { + for (i = 0; i < (sizeof(code2xy_data) / sizeof(code2xy_data[0])); i++) { TEST_ASSERT_TRUE(get_xy_by_code(code2xy_data[i].code, &out)); TEST_ASSERT_EQUAL_INT32(code2xy_data[i].x, out.x); TEST_ASSERT_EQUAL_INT32(code2xy_data[i].y, out.y); @@ -118,22 +117,20 @@ void test_get_xy_by_code(void) void test_get_zone_by_location(void) { zone_t out; + loc_t loc; + uint32_t i; - for (uint32_t i = 0; i < (sizeof(code2hex_data) / sizeof(code2hex_data[0])); i++) { - loc_t loc = { - .lat = code2hex_data[i].lat, - .lon = code2hex_data[i].lon, - }; + for (i = 0; i < (sizeof(code2hex_data) / sizeof(code2hex_data[0])); i++) { + loc.lat = code2hex_data[i].lat; + loc.lon = code2hex_data[i].lon; TEST_ASSERT_TRUE(get_zone_by_location(&loc, strlen(code2hex_data[i].code) - 2, &out)); TEST_ASSERT_EQUAL_STRING(code2hex_data[i].code, out.code); } - for (uint32_t i = 0; i < sizeof(coord2hex_data) / sizeof(coord2hex_data[0]); i++) { - loc_t loc = { - .lat = coord2hex_data[i].lat, - .lon = coord2hex_data[i].lon, - }; + for (i = 0; i < sizeof(coord2hex_data) / sizeof(coord2hex_data[0]); i++) { + loc.lat = coord2hex_data[i].lat; + loc.lon = coord2hex_data[i].lon; TEST_ASSERT_TRUE(get_zone_by_location(&loc, coord2hex_data[i].level, &out)); TEST_ASSERT_EQUAL_STRING(coord2hex_data[i].code, out.code); @@ -143,8 +140,9 @@ void test_get_zone_by_location(void) void test_get_zone_by_code(void) { zone_t out; + uint32_t i; - for (uint32_t i = 0; i < (sizeof(code2hex_data) / sizeof(code2hex_data[0])); i++) { + for (i = 0; i < (sizeof(code2hex_data) / sizeof(code2hex_data[0])); i++) { TEST_ASSERT_TRUE(get_zone_by_code(code2hex_data[i].code, &out)); TEST_ASSERT_DOUBLE_WITHIN(15, code2hex_data[i].lat, out.latlon.lat); TEST_ASSERT_DOUBLE_WITHIN(15, code2hex_data[i].lon, out.latlon.lon);