At Factual, we process a lot of spatial data. We’re open-sourcing one of our internal libraries for working with geospatial information, especially geohashes. We want all Clojure programmers to be able to answer questions about coordinates, distances, and polygon intersections. We think this library will be particularly useful in concert with our rich suite of location data APIs.
We unify three open-source JVM geospatial libraries: The JTS topology library, spatial4j, and geohash-java. Clojure protocols allow these libraries’ disparate representations of points and shapes to interoperate, so you can, for instance, ask whether a JTS point is within a geohash, or whether a geohash intersects a spatial4j multipolygon.
In addition, we provide common scales and translation functions for unit conversion: converting between steradians and surface areas; finding the radius along the geoid, and some basic properties.
For instance, we can find the distance between a pair of airports:
user=> (def lhr (spatial/spatial4j-point 51.477500 -0.461388))
user=> (def lax (spatial/spatial4j-point 33.942495 -118.408067))
user=> (/ (spatial/distance lhr lax) 1000)
8780.16854531993 ; kilometers
Explore relationships between geographic regions:
user=> (def london (spatial/spatial4j-point 51.5072 0.1275))
user=> (spatial/intersects? lhr (spatial/circle london 50000))
Or transform regions into covering geohashes:
(-> lhr (spatial/circle 1000) (geohash/geohashes-intersecting 30) (->> (map geohash/string)))
("gcpsv3" "gcpsv4" "gcpsv5" "gcpsv6" "gcpsv7" "gcpsv9" "gcpsvd" "gcpsve" "gcpsvf" "gcpsvg" "gcpsvh" "gcpsvk" "gcpsvs" "gcpsvu")
This library is incomplete; in particular, it is not as fast as it could be, encounters bounded errors when translating between various geoid representations, and is subject to singularities at the poles. Nonetheless, we hope that it can be a canonical resource for geospatial computation in Clojure. Check out factual/geo on github!