Skip to main content

High-performance geospatial processing with GPU acceleration, Numba JIT, and format conversion

Project description

GeoFast

High-performance geospatial processing framework: an aerial-spray line-generation engine (compiled Rust), GPU acceleration, Numba JIT compilation, file format conversion, and intelligent caching.

Features

  • Aerial spray line generation: compiled Rust engine (ellipsoidal projection, sweep-angle search, per-gap fly-through-vs-turn, boustrophedon cell decomposition) producing crop-spraying coverage paths
  • Multi-backend execution: CPU, CPU Parallel, GPU (CUDA), Numba JIT, Hybrid
  • Automatic backend selection: Based on data size and available hardware
  • File format conversion: GeoJSON, KML, GPX, CSV, MPZ/MapPlus
  • Numba JIT primitives: Point-in-polygon, haversine, Douglas-Peucker, hex grids
  • Spatial indexing: R-tree, hex grid index, point index
  • GPU kernels: CUDA acceleration via Numba CUDA and CuPy
  • Intelligent caching: Memory and disk caching for expensive computations
  • Command-line interface: Convert files, view system info, manage cache

Installation

# Basic installation (CPU only)
pip install geofast

# With Numba JIT support (recommended)
pip install geofast[full]

# With GPU support (requires NVIDIA GPU + CUDA)
pip install geofast[gpu]

# Everything
pip install geofast[all]

Prebuilt wheels bundle the compiled spray engine, so pip install geofast needs no Rust toolchain. numpy and shapely are installed by default. A Rust toolchain is only required when building from source (an sdist or a git checkout), which is handled automatically by maturin.

Quick Start

Spray Pattern Generation

from geofast import generate_spray_patterns

# Read a field boundary (GeoJSON/KML/...), generate spray lines, write the result.
# The Rust engine selects the spray angle and decomposes the field itself.
generate_spray_patterns(
    "field.geojson", "spray.geojson",
    config={"swath_width_ft": 50.0},
)

For finer control, the generator and optimizer are available directly:

from geofast.spray_line_generator import SprayLineGenerator, SprayConfig

gen = SprayLineGenerator(SprayConfig(swath_width_ft=50.0))
result = gen.generate(field_coords)  # field_coords: GeoJSON polygon rings, lon/lat degrees
print(result.num_lines, result.total_spray_distance_miles, result.field_area_acres)

File Format Conversion

from geofast import convert, read_kml, MPZReader

# Convert between formats (auto-detects from extension)
convert('tracks.kml', 'tracks.geojson')
convert('field.geojson', 'field.kml')
convert('points.csv', 'points.gpx')

# Read KML directly
data = read_kml('file.kml')  # Returns GeoJSON-like dict

# Read MapPlus/MPZ files
with MPZReader('data.mpz') as reader:
    tracks = reader.get_tracks()
    polygons = reader.get_polygons()
    geojson = reader.to_geojson()

High-Performance Primitives

from geofast import (
    haversine_scalar, haversine_batch,
    point_in_polygon, points_in_polygon_batch,
    douglas_peucker,
    lat_lon_to_hex, polygon_to_hex_cells,
)
import numpy as np

# Fast haversine distance (Numba JIT)
dist = haversine_scalar(lat1, lon1, lat2, lon2, radius=3959)  # miles

# Batch operations (parallel)
lats1 = np.array([40.0, 41.0, 42.0])
lons1 = np.array([-74.0, -73.0, -72.0])
distances = haversine_batch(lats1, lons1, lats2, lons2)

# Point-in-polygon (Numba JIT)
poly_x = np.array([0, 1, 1, 0, 0], dtype=np.float64)
poly_y = np.array([0, 0, 1, 1, 0], dtype=np.float64)
inside = point_in_polygon(0.5, 0.5, poly_x, poly_y)  # True

# Line simplification
coords = np.array([[0, 0], [1, 0.1], [2, 0], [3, 0.1], [4, 0]])
simplified = douglas_peucker(coords, epsilon=0.2)

# Hex grid operations
q, r = lat_lon_to_hex(40.7128, -74.0060, hex_size_lat=0.001, hex_size_lon=0.001)

Spatial Indexing

from geofast import SpatialIndex, HexGridIndex

# R-tree index for fast polygon queries
index = SpatialIndex()
index.add_polygon('field1', polygon_coords)
index.add_polygon('field2', polygon_coords)
index.build()

# O(log n) point query
hits = index.query_point(lon, lat)

# Hex grid index for O(1) lookups
hex_index = HexGridIndex(hex_size_lat=0.001, hex_size_lon=0.001)
hex_index.add_polygons(polygons_dict)
hex_index.build()
field_ids = hex_index.query_point(lat, lon)

GPU Acceleration

from geofast import haversine_auto, hex_keys_auto, gpu_available

# Automatically uses GPU for large arrays, CPU for small
distances = haversine_auto(lats1, lons1, lats2, lons2)
q_arr, r_arr = hex_keys_auto(lats, lons, hex_size_lat, hex_size_lon)

# Check GPU availability
if gpu_available():
    print("GPU acceleration available!")

Caching

from geofast import (
    get_polygon_cell_cache,
    cached,
    set_cache_config,
    print_cache_stats,
)

# Enable/configure caching
set_cache_config(enabled=True, cache_dir='~/.geofast/cache')

# Cache expensive computations
cache = get_polygon_cell_cache()
cells = cache.get_or_compute(polygon, hex_lat, hex_lon, compute_func)

# Decorator for automatic caching
@cached(cache_type='disk', ttl=3600)
def expensive_computation(data):
    ...

# View cache statistics
print_cache_stats()

Decorator-based Backend Selection

from geofast import process, Backend

# Auto-select best backend based on data size
@process(backend=Backend.AUTO, item_count_arg="geometries")
def simplify_fields(geometries, tolerance=0.001):
    from shapely import simplify
    return list(simplify(geometries, tolerance))

# Force GPU with CPU fallback
@process(backend=Backend.GPU, fallback=Backend.CPU)
def compute_distances(lats1, lons1, lats2, lons2):
    ...

# Parallel file processing
@process(backend=Backend.CPU_PARALLEL, batch=True)
def convert_files(filepaths):
    ...

Command Line Interface

# Convert files
geofast convert input.kml output.geojson
geofast convert tracks.mpz tracks.geojson

# Show system info
geofast info
geofast info --cache

# Manage cache
geofast cache --stats
geofast cache --clear

# List supported formats
geofast formats

Supported File Formats

Format Read Write Notes
GeoJSON .geojson, .json
KML .kml
GPX .gpx (tracks, waypoints, routes)
CSV Requires lat/lon columns
MPZ/MapPlus .mpz, .sdb (SQLite-based)
Shapefile Requires fiona

Backends

Backend Best For Requirements
CPU Small datasets, simple operations numpy
CPU_PARALLEL File I/O, embarrassingly parallel tasks numpy
GPU Large arrays (10k+), matrix operations cupy
NUMBA Tight loops, custom algorithms numba
NUMBA_CUDA Custom GPU kernels numba + CUDA
HYBRID Very large datasets, max throughput all
AUTO Let GeoFast decide any

Configuration

from geofast import set_config

set_config(
    max_workers=8,           # CPU cores to use
    chunk_size=1000,         # Items per parallel chunk
    gpu_batch_size=10000,    # Items per GPU batch
    auto_gpu_min_items=1000, # Threshold for AUTO->GPU
    verbose=True             # Log backend selection
)

Performance

Benchmarks on a system with 16 CPU cores and NVIDIA RTX 4050:

Operation Original With GeoFast Speedup
Polygon cell computation (7352 polygons) ~20s 1.3s (cached) 15x
Track processing (262 tracks) ~60s 10.7s 5.6x
Point-in-polygon (batch) ~30s 4.7s 6.4x
Full analysis pipeline ~300s 41s 7.3x

Spray Pattern Generation

Generate optimal spray lines for agricultural fields:

from geofast import generate_spray_patterns

# Generate spray lines from field boundaries
generate_spray_patterns(
    'fields.kml',           # Input: field polygons
    'spray_lines.geojson',  # Output: spray lines + boundaries
    config={
        'swath_width_ft': 50,    # Spray width per pass
        'hop_distance_ft': 1300  # Max gap for pilot hopping
    }
)

Features

  • Optimal direction selection: Automatically chooses N-S or E-W based on field shape
  • Multi-field optimization: Groups nearby fields for consistent spray direction
  • Powerline detection: Flags fields with hasPowerlines: true when transmission lines intersect
  • Efficiency metrics: Calculates acres/hour, total time, line counts

Command Line

# Basic usage
geofast spray field.kml lines.geojson

# With options
geofast spray field.kml lines.geojson --swath 60 --metadata

# Ground operations (no hopping)
geofast spray field.kml lines.geojson --no-hop

Output Properties

Each field boundary in the output includes:

  • hasPowerlines: Boolean indicating if powerlines cross the field
  • angle: Optimal spray direction (0=N-S, 90=E-W)
  • acres: Field area
  • num_tracks: Number of spray passes

Project Structure

geofast/
├── __init__.py      # Package exports
├── core.py          # Backend enum, @process decorator
├── executor.py      # Backend dispatch logic
├── primitives.py    # Numba JIT functions
├── spatial_index.py # R-tree, hex grid indexing
├── cuda_kernels.py  # GPU kernels (CUDA/CuPy)
├── parallel.py      # Shared memory, parallel utilities
├── geo_ops.py       # High-level geo operations
├── formats.py       # File format converters
├── cache.py         # Caching layer
├── cli.py           # Command-line interface
└── utils.py         # Detection, helpers

Requirements

  • Python 3.9+
  • numpy

Optional

  • numba (for JIT compilation)
  • shapely 2.0+ (for spatial operations)
  • cupy (for GPU acceleration)
  • geopandas, fiona (for shapefile support)

License

MIT License - see LICENSE file for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

geofast-0.5.0.tar.gz (75.8 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

geofast-0.5.0-cp39-abi3-win_amd64.whl (482.5 kB view details)

Uploaded CPython 3.9+Windows x86-64

geofast-0.5.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (611.9 kB view details)

Uploaded CPython 3.9+manylinux: glibc 2.17+ x86-64

geofast-0.5.0-cp39-abi3-macosx_11_0_arm64.whl (540.5 kB view details)

Uploaded CPython 3.9+macOS 11.0+ ARM64

File details

Details for the file geofast-0.5.0.tar.gz.

File metadata

  • Download URL: geofast-0.5.0.tar.gz
  • Upload date:
  • Size: 75.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: maturin/1.14.1

File hashes

Hashes for geofast-0.5.0.tar.gz
Algorithm Hash digest
SHA256 1d427bed91bd231058d71bd0af4cce7ff8ae8136d2918f3d6732e0f1bbfa9966
MD5 bff82413b505089f68927cdb32f108e1
BLAKE2b-256 2bb99621df09172b49e47143cfedae5dabb8fda56be980859613033274531d3f

See more details on using hashes here.

File details

Details for the file geofast-0.5.0-cp39-abi3-win_amd64.whl.

File metadata

  • Download URL: geofast-0.5.0-cp39-abi3-win_amd64.whl
  • Upload date:
  • Size: 482.5 kB
  • Tags: CPython 3.9+, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: maturin/1.14.1

File hashes

Hashes for geofast-0.5.0-cp39-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 4bafacd6e0863a3a7a127ced76c7dda58ff6007e00f7d33391fe641414d7145b
MD5 9cf6d3bfefbc37d5bbc8b5c1181e924c
BLAKE2b-256 d468658d1cecd23890459b263f566403e37adfffb55fa19af0cb86463ab5bbe3

See more details on using hashes here.

File details

Details for the file geofast-0.5.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for geofast-0.5.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 0c1c998e7b6150c17f4cbe6aa8ba52bc7069a4f61b4ad929425b72e4121d0a00
MD5 2bc742c96df99a83b8ec67cbab4e514d
BLAKE2b-256 2221c3d3b0cbe607ab9ec3b651a865d2293003a9705d37e7829cf0030ab2143a

See more details on using hashes here.

File details

Details for the file geofast-0.5.0-cp39-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for geofast-0.5.0-cp39-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 61deb811989dc7aa66713fdf5d5e54ca8ee1f7efe8c57f6dbee4288ed3e84566
MD5 b8f283fadfbcffbc8cbfae9145d1132b
BLAKE2b-256 707bf1cf4887f7b3b6c4fd45b8b1c9a9b9c1ab511832f9f171cd3aae3b34891c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page