Skip to content

Repository files navigation

geo4k

Lightweight geofencing and point-in-polygon for the JVM and the browser, written in Kotlin.

Answer "which of these zones contains this point?" fast, over many polygons — without pulling in a whole GIS stack. The "I just need geofencing, not GeoTools" case.

Status: early / work in progress. Geometry types, ray-casting point-in-polygon, a Geofence spatial index (containing(point)), supporting geometry (area, centroid, haversine), and a JMH benchmark are in, with tests. A live browser demo is next. Not yet published to Maven Central.

Why

Lots of services need one geospatial answer — is this GPS point inside a charging zone, a delivery area, a catchment? — and reach for a full GIS library (JTS, GeoTools) to get it. geo4k is the small alternative: a hand-written point-in-polygon test plus a spatial index so "which of many zones" stays fast, Kotlin-idiomatic, dependency-free, and compiled to both the JVM and the browser.

Example

val zone = Polygon(listOf(Point(0.0, 0.0), Point(4.0, 0.0), Point(4.0, 4.0), Point(0.0, 4.0)))

val inside: Boolean = Point(2.0, 2.0) in zone   // true

Index many zones and ask which contain a point — the spatial grid prunes to a handful of candidates before the exact test, so it stays fast as the zone count grows:

val fence = Geofence.of(
    Zone("congestion", Polygon(/* … */)),
    Zone("ulez", Polygon(/* … */)),
)
val here: List<Zone> = fence.containing(Point(-0.12, 51.51))   // [congestion, ulez]

Planar by design

geo4k works in the plane (Cartesian): map longitude to x, latitude to y. Edges are straight lines, not geodesics, and there is no projection / CRS handling. That is accurate enough for city-scale geofencing — the target case — and is exactly what keeps the library small and dependency-free. If you need geodesic edges, datums or reprojection you need a real GIS stack, and that is the line geo4k does not cross.

Benchmark

./gradlew :benchmark:jmh runs the JMH benchmark: the Geofence index versus a naive scan of every zone, for the same "which zones contain this point?" query, as the zone count grows.

zones indexed naive scan speed-up
100 ~8 ns ~250 ns ~30×
1,000 ~97 ns ~4,550 ns ~47×
10,000 ~530 ns ~118,000 ns ~220×

The naive scan grows linearly with the zone count; the indexed query stays far flatter (grid pruning), so the gap widens as zones grow. (JMH average time, 2 forks × 5 iterations; machine-dependent — run it yourself.)

Building

./gradlew build

Requires a JDK; the Gradle wrapper fetches the rest.

Licence

MIT.

About

Lightweight geofencing and point-in-polygon for the JVM and the browser, in Kotlin.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages