Skip to content

JuliaGeo/TGGeometry.jl

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

22 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

TGGeometry

TG logo

TGGeometry.jl is a Julia wrapper around the tg C library for planar geometric predicates. Specifically, it provides:

  • intersects(geom1, geom2)
  • contains(geom1, geom2)
  • touches(geom1, geom2)
  • disjoint(geom1, geom2)
  • equals(geom1, geom2)
  • covers(geom1, geom2)
  • coveredby(geom1, geom2)
  • within(geom1, geom2)

from the DE-9IM model.

It is fully GeoInterface.jl compatible, and is able to accept any combination of GeoInterface-compatible geometries as input (from GeoDataFrames, GeoJSON, ArchGDAL, GeometryOps, and many more packages!).

It also provides a GeoInterface.jl-compatible type, TGGeom, which can be used to wrap the C-level tg_geom objects returned by the tg library - in case you want complete speed. You can convert any GeoInterface-compatible geometry to a TGGeom using GeoInterface.convert(TGGeom, geom), or GeoInterface.convert(TGGeometry, geom). Similarly, you can convert a TGGeom back to any GeoInterface-compatible geometry using the same function

Quick start

Installation

Install via ]add TGGeometry in the REPL, or Pkg.add("TGGeometry").

Basic usage

Since TGGeometry allows any GeoInterface-compatible geometry as input, let's start with some geometries from NaturalEarth.jl:

using NaturalEarth
all_countries = naturalearth("admin_0_countries", 10)
germany = all_countries.geometry[findfirst(==("Germany"), all_countries.NAME)]
belgium = all_countries.geometry[findfirst(==("Belgium"), all_countries.NAME)]

using TGGeometry
TGGeometry.intersects(germany, belgium) # true
TGGeometry.contains(germany, belgium) # false
TGGeometry.touches(germany, belgium) # true
TGGeometry.disjoint(germany, belgium) # false

You can use any data loader, like GeoJSON, GeoDataFrames, ArchGDAL, etc. You can also construct your own geometries via GeometryBasics, GeoInterface wrapper geometries, or accepted basic types like 2-tuple points.

berlin = (13.4050, 52.5200) # berlin (latitude, longitude)

TGGeometry.contains(germany, berlin) # true

"Preparing" using TGGeom

TGGeometry is fast naturally, but you can make it even faster by "preparing" your geometries by converting them to TGGeoms. This converts the geometries to opaque pointers to a tg geometry - still fully GeoInterface-compatible though, but they have the acceleration benefits and don't have to be continually converted every time you call a predicate.

The way to convert is to call GeoInterface.convert(TGGeometry, geom). This will convert the geometry to a TGGeom and return the new TGGeom object.

Let's see the difference in speed, between using a TGGeom and a GeoJSON polygon:

using Chairmarks, GeoInterface
gj_bench = @be TGGeometry.contains($germany, $berlin)
Benchmark: 2014 samples with 1 evaluation
 min    21.375 μs (72 allocs: 49.891 KiB)
 median 32.791 μs (72 allocs: 49.891 KiB)
 mean   44.772 μs (72 allocs: 49.891 KiB, 0.64% gc time)
 max    2.290 ms (72 allocs: 49.891 KiB, 96.10% gc time)
# Convert to TGGeom
germany_tg = GeoInterface.convert(TGGeometry, germany)

tg_bench = @be TGGeometry.contains($germany_tg, $berlin)
Benchmark: 2355 samples with 305 evaluations
 min    78.279 ns (1 allocs: 16 bytes)
 median 94.262 ns (1 allocs: 16 bytes)
 mean   131.635 ns (1 allocs: 16 bytes, 0.04% gc time)
 max    85.267 μs (1 allocs: 16 bytes, 99.75% gc time)

The prepared approach is about 340x faster!