Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions .github/workflows/format.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,15 @@ jobs:
name: Format
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.x"
- name: Cache pre-commit
uses: actions/cache@v4
with:
path: ~/.cache/pre-commit
key: pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
restore-keys: |
pre-commit-
- uses: pre-commit/action@v3.0.0
14 changes: 14 additions & 0 deletions .github/workflows/pip.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,20 @@ jobs:
python-version: ${{ matrix.python-version }}
allow-prereleases: true

- name: Get pip cache dir
id: pip-cache
shell: bash
run: echo "dir=$(pip cache dir)" >> $GITHUB_OUTPUT

- name: Cache pip dependencies
uses: actions/cache@v4
with:
path: ${{ steps.pip-cache.outputs.dir }}
key: ${{ runner.os }}-pip-${{ matrix.python-version }}-${{ hashFiles('pyproject.toml') }}
restore-keys: |
${{ runner.os }}-pip-${{ matrix.python-version }}-
${{ runner.os }}-pip-

- name: Add requirements
run: python -m pip install --upgrade wheel setuptools

Expand Down
32 changes: 17 additions & 15 deletions .github/workflows/wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,40 +44,42 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, macos-14]

steps:
- uses: actions/checkout@v4
with:
submodules: true

- name: Set up QEMU
if: runner.os == 'Linux'
uses: docker/setup-qemu-action@v2
- name: Cache cibuildwheel
uses: actions/cache@v4
with:
platforms: all
path: |
~/Library/Caches/pip
~/.cache/pip
~/AppData/Local/pip/Cache
key: cibw-pip-${{ matrix.os }}-${{ hashFiles('pyproject.toml') }}
restore-keys: |
cibw-pip-${{ matrix.os }}-

- uses: pypa/cibuildwheel@v2.22
env:
# CIBW_ARCHS: auto64
CIBW_ARCHS_LINUX: x86_64 aarch64
CIBW_ARCHS_WINDOWS: AMD64 # ARM64
CIBW_ARCHS_MACOS: x86_64 arm64
CIBW_BEFORE_BUILD: pip install numpy fire --prefer-binary
# https://cibuildwheel.readthedocs.io/en/stable/options/#build-skip
CIBW_SKIP: pp* *i686 *musllinux*
CIBW_ARCHS_MACOS: universal2
CIBW_ARCHS_WINDOWS: AMD64 ARM64
CIBW_SKIP: "pp* *musllinux* *_i686"
CIBW_TEST_SKIP: "*macosx* *win* *aarch64"
CIBW_BEFORE_BUILD: "pip install --prefer-binary numpy fire pytest"

- name: Verify clean directory
run: git diff --exit-code
shell: bash

- name: Upload wheels
uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v4
with:
name: cibw-wheels-${{ matrix.os }}
name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }}
path: wheelhouse/*.whl


upload_all:
name: Upload if release
needs: [build_wheels, build_sdist]
Expand Down
3 changes: 0 additions & 3 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,3 @@
[submodule "pygeobuf"]
path = pygeobuf
url = https://github.com/pygeobuf/pygeobuf.git
[submodule "headers"]
path = headers
url = https://github.com/cubao/headers.git
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ repos:

# Changes tabs to spaces
- repo: https://github.com/Lucas-C/pre-commit-hooks
rev: v1.1.13
rev: v1.5.6
hooks:
- id: remove-tabs
exclude: ^(docs|Makefile|benchmarks/Makefile)
Expand Down
68 changes: 68 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

C++ port of [mapbox/geobuf](https://github.com/mapbox/geobuf) with Python bindings via pybind11. Geobuf is a compact binary encoding for GeoJSON using Protocol Buffers.

## Build Commands

```bash
# Initialize submodules (required first time)
git submodule update --init --recursive

# Build Python extension (editable install)
make build

# Run all C++ tests
make test_all

# Run Python tests
make pytest
# Or directly: pytest tests/test_basic.py

# Lint code
make lint

# Roundtrip tests (compare C++ vs JS implementations)
make roundtrip_test_cpp
make roundtrip_test_js

# CLI tests
make cli_test
```

## Architecture

### Core C++ Library (`src/geobuf/`)

- **geobuf.hpp/cpp**: Main `Encoder` and `Decoder` classes for GeoJSON ↔ Geobuf (protobuf) conversion
- **geobuf_index.hpp**: `GeobufIndex` class for spatial indexing and random access to features in large Geobuf files using memory-mapped I/O and packed R-tree
- **planet.hpp**: `Planet` class wrapping feature collections with spatial query support via `PackedRTree`
- **geojson_helpers.hpp**: JSON normalization utilities (rounding, sorting keys, denoising)
- **rapidjson_helpers.hpp**: RapidJSON wrapper utilities

### Python Bindings (`src/`)

- **main.cpp**: pybind11 module definition exposing `Encoder`, `Decoder`, `GeobufIndex`, `Planet`, `PackedRTree`
- **pybind11_geojson.cpp**: Bindings for mapbox::geojson types (Point, LineString, Polygon, Feature, FeatureCollection)
- **pybind11_rapidjson.cpp**: Bindings for RapidJSON value types

### Key Dependencies (all header-only, in submodules)

- `rapidjson`: JSON parsing/serialization
- `geojson-cpp` (forked): GeoJSON representation with Z-coordinate and custom_properties support
- `protozero`: Protocol Buffer encoding/decoding
- `geometry.hpp` (forked): Geometry types

### Python Package (`src/pybind11_geobuf/`)

- CLI via `python -m pybind11_geobuf` with commands: `json2geobuf`, `geobuf2json`, `pbf_decode`, `normalize_json`, `round_trip`, `is_subset_of`

## Key Classes

- `mapbox::geobuf::Encoder`: Encodes GeoJSON to compact Geobuf format with configurable precision
- `mapbox::geobuf::Decoder`: Decodes Geobuf back to GeoJSON, supports partial decoding (header, individual features)
- `cubao::GeobufIndex`: Enables random access to features in large Geobuf files without loading entire file
- `cubao::Planet`: Feature collection with built-in spatial index for bounding box queries
12 changes: 10 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-pragma-once-outside-header")
endif()

if(MSVC)
add_compile_options(/bigobj)
endif()

add_definitions(-D_CRT_SECURE_NO_WARNINGS)
add_definitions(-DPROJECT_SOURCE_DIR="${PROJECT_SOURCE_DIR}")
add_definitions(-DPROJECT_BINARY_DIR="${PROJECT_BINARY_DIR}")
Expand All @@ -34,7 +38,11 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_CXX_STANDARD 17)
include_directories(SYSTEM ${PROJECT_SOURCE_DIR}/headers/include)
execute_process(
COMMAND "${Python_EXECUTABLE}" -c "import cubao_headers; print(cubao_headers.get_include())"
OUTPUT_VARIABLE CUBAO_HEADERS_INCLUDE_DIR
OUTPUT_STRIP_TRAILING_WHITESPACE)
include_directories(SYSTEM ${CUBAO_HEADERS_INCLUDE_DIR})
include_directories(${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/src ${PROJECT_SOURCE_DIR}/src/geobuf)

option(BUILD_SHARED_LIBS "Build shared library." OFF)
Expand All @@ -44,7 +52,7 @@ file(GLOB_RECURSE SOURCES src/**/*.cpp)
add_library(${PROJECT_NAME} ${SOURCES} ${HEADERS})
target_link_libraries(${PROJECT_NAME} ${CONAN_LIBS})
set_target_properties(${PROJECT_NAME} PROPERTIES CXX_VISIBILITY_PRESET "hidden")
install(TARGETS ${PROJECT_NAME} DESTINATION ${PROJECT_NAME})
# Don't install static library to wheel - delocate-wheel can't handle .a files

add_executable(pbf_decoder src/geobuf/pbf_decoder.cpp)
target_compile_definitions(pbf_decoder PUBLIC -DPBF_DECODER_ENABLE_MAIN)
Expand Down
3 changes: 0 additions & 3 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
include README.md LICENSE pybind11/LICENSE
include CMakeLists.txt
graft headers/include
graft pybind11/include
graft pybind11/tools
graft src
graft examples
graft tests
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ cli_test: cli_test1 cli_test2 cli_test3 cli_test4
restub:
pybind11-stubgen pybind11_geobuf._core -o stubs
cp -rf stubs/pybind11_geobuf/_core src/pybind11_geobuf
# Fix duplicate parameter names generated by pybind11-stubgen
sed -i '' 's/new_value: \.\.\., std: \.\.\., std: \.\.\., mapbox: \.\.\., std: \.\.\., std: \.\.\., std: \.\.\., std: \.\.\., std: \.\.\., std: \.\.\., std: \.\.\., std: \.\.\., std: \.\.\., mapbox: \.\.\./new_value: .../g' src/pybind11_geobuf/_core/geojson.pyi
pre-commit run --files src/pybind11_geobuf/_core/*.pyi || pre-commit run --files src/pybind11_geobuf/_core/*.pyi

test_all:
@cd build && for t in $(wildcard $(BUILD_DIR)/test_*); do echo $$t && eval $$t >/dev/null 2>&1 && echo 'ok' || echo $(RED)Not Ok$(NC); done
Expand Down
1 change: 0 additions & 1 deletion headers
Submodule headers deleted from 0a21ab
13 changes: 10 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
[build-system]
requires = ["scikit-build-core>=0.3.3", "pybind11"]
requires = ["scikit-build-core>=0.3.3", "pybind11", "cubao-headers>=0.1.0"]
build-backend = "scikit_build_core.build"


[project]
name = "pybind11_geobuf"
version = "0.2.3"
version = "0.2.4"
description="c++ geobuf with python binding"
readme = "README.md"
authors = [
{ name = "district10", email = "dvorak4tzx@gmail.com" },
]
dependencies = [
"fire",
"loguru",
"numpy",
]
requires-python = ">=3.7"
classifiers = [
"Development Status :: 4 - Beta",
Expand All @@ -22,6 +27,8 @@ classifiers = [
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
]


Expand All @@ -30,7 +37,7 @@ Homepage = "https://geobuf-cpp.readthedocs.io"


[project.optional-dependencies]
test = ["pytest", "scipy"]
test = ["pytest"]


[tool.scikit-build]
Expand Down
Loading
Loading