Types and utilities for working with 2d geometry in Golang

orb CI codecov Go Report Card Go Reference

Package orb defines a set of types for working with 2d geo and planar/projected geometric data in Golang. There are a set of sub-packages that use these types to do interesting things. They each provider their own README with extra info.

Interesting features

  • Simple types - allow for natural operations using the make, append, len, [s:e] builtins.
  • GeoJSON - support as part of the geojson sub-package.
  • Mapbox Vector Tile - encoding and decoding as part of the encoding/mvt sub-package.
  • Direct to type from DB query results - by scanning WKB data directly into types.
  • Rich set of sub-packages - including clipping, simplifing, quadtree and more.

Type definitions

type Point [2]float64
type MultiPoint []Point

type LineString []Point
type MultiLineString []LineString

type Ring LineString
type Polygon []Ring
type MultiPolygon []Polygon

type Collection []Geometry

type Bound struct { Min, Max Point }

Defining the types as slices allows them to be accessed in an idiomatic way using Go's built-in functions such at make, append, len and with slice notation like [s:e]. For example:

ls := make(orb.LineString, 0, 100)
ls = append(ls, orb.Point{1, 1})
point := ls[0]

Shared Geometry interface

All of the base types implement the orb.Geometry interface defined as:

type Geometry interface {
	GeoJSONType() string
	Dimensions() int // e.g. 0d, 1d, 2d
	Bound() Bound
}

This interface is accepted by functions in the sub-packages which then act on the base types correctly. For example:

l := clip.Geometry(bound, geom)

will use the appropriate clipping algorithm depending on if the input is 1d or 2d, e.g. a orb.LineString or a orb.Polygon.

Only a few methods are defined directly on these type, for example Clone, Equal, GeoJSONType. Other operation that depend on geo vs. planar contexts are defined in the respective sub-package. For example:

  • Computing the geo distance between two point:

      p1 := orb.Point{-72.796408, -45.407131}
      p2 := orb.Point{-72.688541, -45.384987}
    
      geo.Distance(p1, p2)
    
  • Compute the planar area and centroid of a polygon:

      poly := orb.Polygon{...}
      centroid, area := planar.CentroidArea(poly)
    

GeoJSON

The geojson sub-package implements Marshalling and Unmarshalling of GeoJSON data. Features are defined as:

type Feature struct {
	ID         interface{}  `json:"id,omitempty"`
	Type       string       `json:"type"`
	Geometry   orb.Geometry `json:"geometry"`
	Properties Properties   `json:"properties"`
}

Defining the geometry as an orb.Geometry interface along with sub-package functions accepting geometries allows them to work together to create easy to follow code. For example, clipping all the geometries in a collection:

fc, err := geojson.UnmarshalFeatureCollection(data)
for _, f := range fc {
	f.Geometry = clip.Geometry(bound, f.Geometry)
}

Mapbox Vector Tiles

The encoding/mvt sub-package implements Marshalling and Unmarshalling MVT data. This package uses sets of geojson.FeatureCollection to define the layers, keyed by the layer name. For example:

collections := map[string]*geojson.FeatureCollection{}

// Convert to a layers object and project to tile coordinates.
layers := mvt.NewLayers(collections)
layers.ProjectToTile(maptile.New(x, y, z))

// In order to be used as source for MapboxGL geometries need to be clipped
// to max allowed extent. (uncomment next line)
// layers.Clip(mvt.MapboxGLDefaultExtentBound)

// Simplify the geometry now that it's in tile coordinate space.
layers.Simplify(simplify.DouglasPeucker(1.0))

// Depending on use-case remove empty geometry, those too small to be
// represented in this tile space.
// In this case lines shorter than 1, and areas smaller than 2.
layers.RemoveEmpty(1.0, 2.0)

// encoding using the Mapbox Vector Tile protobuf encoding.
data, err := layers.Marshal() // this data is NOT gzipped.

// Sometimes MVT data is stored and transfered gzip compressed. In that case:
data, err := layers.MarshalGzipped()

Decoding WKB from a database query

Geometries are usually returned from databases in WKB format. The encoding/wkb sub-package offers helpers to "scan" the data into the base types directly. For example:

row := db.QueryRow("SELECT ST_AsBinary(point_column) FROM postgis_table")

var p orb.Point
err := row.Scan(wkb.Scanner(&p))

db.Exec("INSERT INTO table (point_column) VALUES (ST_GeomFromWKB(?))", wkb.Value(p))

Scanning directly from MySQL columns is supported. By default MySQL returns geometry data as WKB but prefixed with a 4 byte SRID. To support this, if the data is not valid WKB, the code will strip the first 4 bytes, the SRID, and try again. This works for most use cases.

List of sub-package utilities

  • clip - clipping geometry to a bounding box
  • encoding/mvt - encoded and decoding from Mapbox Vector Tiles
  • encoding/wkb - well-known binary as well as helpers to decode from the database queries
  • encoding/wkt - well-known text encoding
  • geojson - working with geojson and the types in this package
  • maptile - working with mercator map tiles
  • project - project geometries between geo and planar contexts
  • quadtree - quadtree implementation using the types in this package
  • resample - resample points in a line string geometry
  • simplify - linear geometry simplifications like Douglas-Peucker
Comments
  • wkb: simplify byte order code

    wkb: simplify byte order code

    this PR refactors encoding/wkb/* to remove the custom type type byteOrder int and replace it with binary.ByteOrder. it also removes the constants const bigEndian and const littleEndian.

    this actually simplifies the code a fair bit since there is no need to write if conditions based on the desired endianness.

    let me know if this is something you'd consider merging and if there's anything else which needs to be done.

    I noticed a fair amount of code duplication between byteOrderType() & readByteOrderType(), I also considered refactoring those functions but didn't go that far in this PR.

  • Add support for time data on Features as proposed in geojson-ld

    Add support for time data on Features as proposed in geojson-ld

    Add support for datetime information over Features as discussed at https://github.com/geojson/geojson-ld

    • See discution here: geojson/geojson-ld#9
    • See proposal here: https://gist.github.com/sgillies/11404768

    Example:

    {
      "geometry": {
        "coordinates": [
          0.0,
          0.0
        ],
        "type": "Point"
      },
      "id": "1",
      "properties": {"foo": "bar"},
      "type": "Feature",
      "when": {
        "datetime": "2014-04-24",
        "@type": "Instant"
      }
    }
    
  • Add support for EWKB/EWKT

    Add support for EWKB/EWKT

    Hi! We're relying a lot at work on this package to handle geometries, and it works like a charm, but we have an issue when storing geometries inside postgis. We need to specify an SRID for the geometry, to obtain meaningful results with certain database operations, and we are currently converting back and forth between the geometries defined in go-geom and the geometries of orb, which is not ideal performance-wise. We still want to rely on orb for in-memory management of geometries, since it has lots of useful in-memory operations implemented.

    If it's ok with you I'd like to try and submit a PR to add support for EWKB/EWKT serialization. I'm just not sure on how to structure it, and how to share code between the current WKB/WKT implementation, so I'm open to suggestions on this topic.

  • Panic when reading geojson with null geometries in UnmarshallJSON()

    Panic when reading geojson with null geometries in UnmarshallJSON()

    I am writing a program using SA2 geometries from the Australian Statistical Standard Geography which I have converted into geojson with the below code snippet.

    curl http://www.ausstats.abs.gov.au/ausstats/subscriber.nsf/0/A09309ACB3FA50B8CA257FED0013D420/\$File/1270055001_sa2_2016_aust_shape.zip -o ../shapefiles/sa2_2016.zip
    
    unzip ../shapefiles/sa2_2016.zip
    unzip ../shapefiles/ste_2016.zip
    ogr2ogr -f Geojson /SA2_2016_AUST.geojson SA2_2016_AUST.shp
    

    When I try to run my code

    SA2b, _ := ioutil.ReadFile(filename)
    SA2, _ := geojson.UnmarshalFeatureCollection(SA2b)
    

    I receive the following panic error

    panic: runtime error: invalid memory address or nil pointer dereference [recovered]
    	panic: runtime error: invalid memory address or nil pointer dereference
    [signal SIGSEGV: segmentation violation code=0x1 addr=0x10 pc=0x66961f]
    
    goroutine 1 [running]:
    encoding/json.(*decodeState).unmarshal.func1(0xc4200c5c18)
    	/usr/local/go/src/encoding/json/decode.go:175 +0xd4
    panic(0x6e71c0, 0x8eabd0)
    	/usr/local/go/src/runtime/panic.go:502 +0x229
    github.com/paulmach/orb/geojson.(*Feature).UnmarshalJSON(0xc42069b0e0, 0xc4304cdd1f, 0x1d1, 0x783ae33, 0x0, 0x7f318f62d840)
    	/media/fpmpdrive/fpmp/goyulo/src/github.com/paulmach/orb/geojson/feature.go:86 +0x21f
    encoding/json.(*decodeState).object(0xc4200ba240, 0x6efdc0, 0xc4200dfa00, 0x196)
    	/usr/local/go/src/encoding/json/decode.go:626 +0x1c9d
    encoding/json.(*decodeState).value(0xc4200ba240, 0x6efdc0, 0xc4200dfa00, 0x196)
    	/usr/local/go/src/encoding/json/decode.go:408 +0x2d3
    encoding/json.(*decodeState).array(0xc4200ba240, 0x6c8120, 0xc42530c0a8, 0x197)
    	/usr/local/go/src/encoding/json/decode.go:583 +0x1d0
    encoding/json.(*decodeState).value(0xc4200ba240, 0x6c8120, 0xc42530c0a8, 0x197)
    	/usr/local/go/src/encoding/json/decode.go:405 +0x266
    encoding/json.(*decodeState).object(0xc4200ba240, 0x6e83e0, 0xc42530c080, 0x16)
    	/usr/local/go/src/encoding/json/decode.go:776 +0x132d
    encoding/json.(*decodeState).value(0xc4200ba240, 0x6e83e0, 0xc42530c080, 0x16)
    	/usr/local/go/src/encoding/json/decode.go:408 +0x2d3
    encoding/json.(*decodeState).unmarshal(0xc4200ba240, 0x6e83e0, 0xc42530c080, 0x0, 0x0)
    	/usr/local/go/src/encoding/json/decode.go:189 +0x1e7
    encoding/json.Unmarshal(0xc42bd76000, 0xbf92952, 0xbf92b52, 0x6e83e0, 0xc42530c080, 0xbf92952, 0xbf92b52)
    	/usr/local/go/src/encoding/json/decode.go:108 +0x148
    github.com/paulmach/orb/geojson.UnmarshalFeatureCollection(0xc42bd76000, 0xbf92952, 0xbf92b52, 0xbf92952, 0xbf92b52, 0x0)
    	/media/fpmpdrive/fpmp/goyulo/src/github.com/paulmach/orb/geojson/feature_collection.go:58 +0x6e
    main.main()
    	/media/fpmpdrive/fpmp/goyulo/src/yuloserver/main.go:61 +0x225
    exit status 2
    
    

    This was apparently caused missing geometries in the file (for statistical geographical classifications with no true spatial elements) and subsequently a pointer error when UnmarshallJSON. I fixed this by removing features will missing geometries in Python and resaving the file.

    This scenario may well happen again to other users, especially if other data providers include features without spatial elements. Do you think it wise to put a check in to see if the geometry is present, or provide a specific error message?

  • incorrect result from Quadkey()

    incorrect result from Quadkey()

    As per bing maps, given tile XY coordinates of (3, 5) at level 3, the result should be a string “213”.

    But Quadkey() from orb package for the same tile returns a uint64 of 39. Why are the results different? func (t Tile) Quadkey() uint64

  • Would you be open to changing the signatures in maptile/tilecover ?

    Would you be open to changing the signatures in maptile/tilecover ?

    Specifically, changing the return values from maptile.Set to (maptile.Set, error)

    My concern is that the /maptile/tilecover/polygon.go code triggers a panic if it encounters an invalid geometry and it would be helpful for the package to return an error that I can handle in my application code rather than all the scaffolding necessary to trap and recover from a panic.

    I am happy to do the work to produce a PR but figured I would see whether this was interesting to you, first.

  • Issue when retrieving postgis geometry

    Issue when retrieving postgis geometry

    I've spend a couple of hours trying to figure out what doesn't work with my use-case (postgreSQL, postGIS, go-pg and orb)

    I have a complicated SELECT query (2 joins and 1 pivot) that I will simplify for this thread. The problem occurs during the Scan of a polygon

    p := orb.Polygon{}
    _, err := b.Database.Query(wkb.Scanner(&p), `SELECT ST_AsBinary(jobs.region,'NDR') FROM jobs LIMIT 1`, id)
    

    The returned error:

    Expected
              <internal.Error>: {
                  s: "wkb: invalid data",
              }
          to be nil
    

    I dig in the code and found that the error occurs here: https://github.com/paulmach/orb/blob/5af0ae28533d2d7038e9e103c43ccc6d8d0d05a6/encoding/wkb/wkb.go#L218-L244

    I added some logs to print the actual data and I got this:

    \x01030000000200000005000000000000000000000000000000000000000000000000002440000000000000000000000000000024400000000000002440000000000000000000000000000024400000000000000000000000000000000005000000000000000000f03f000000000000f03f000000000000f03f0000000000000040000000000000004000000000000000400000000000000040000000000000f03f000000000000f03f000000000000f03f
    

    which seems to be a perfect WKB apart from the leading \x. When I use a online service like https://rodic.fr/blog/online-conversion-between-geometric-formats/ to convert the data it gives exactly what I inserted in the database --> POLYGON((0 0,10 0,10 10,0 10,0 0),(1 1,1 2,2 2,2 1,1 1))

    Any ideas ?

  • Missing check if tile projected coordinates are in larger extent

    Missing check if tile projected coordinates are in larger extent

    In order to use the generated vector tiles as a source for mapbox all coordinates in a tile must not exceed a certain extent. (https://www.mapbox.com/mapbox-gl-js/style-spec/#sources-vector)

    https://github.com/paulmach/orb/blob/1f34bf6ee9935efca353b8cc0e06396d347cf836/encoding/mvt/projection.go#L27-L31 Maybe the projection could also return if the point should be included or not?

    Was this check left out by choice?

  • encoding/mvt: stable marshalling

    encoding/mvt: stable marshalling

    Hi! We've been using the library and are big fans. I've noticed one opportunity to (potentially) improve things. I'm trying to take an MD5 hash of the marshaled bytes to use as a fingerprint that I can compare with what the client sends me to see if they match, and it doesn't work quite right.

    Currently, encode_properties iterates over a map to encode. Since there are no guarantees on iteration order for go maps, the output can differ each time for the same input. In practice, I've found the iteration order to be different almost every time.

    func TestStableMarshalling(t *testing.T) { layers := NewLayers(loadGeoJSON(t, maptile.New(17896, 24449, 16))) values := make(map[string]bool)

    for i := 0; i < 100; i++ {
    	marshal, _ := Marshal(layers)
    	checksum := md5.Sum(marshal)
    	sum := hex.EncodeToString(checksum[:])
    	values[sum] = true
    }
    
    if len(values) != 1 {
    	t.Errorf("multiple values (%d) for marshalled bytes", len(values))
    }
    

    } The above test will typically produce 100 different md5 values.

    This change makes encode_properties stable by getting the keys to the map, sorting them, and iterating over them. The benchmark numbers are:

    Unstable:

    BenchmarkMarshal
    BenchmarkMarshal-16          	    1819	    606970 ns/op	  368286 B/op	    4790 allocs/op
    BenchmarkUnmarshal
    BenchmarkUnmarshal-16        	    4959	    245290 ns/op	  208822 B/op	    2468 allocs/op
    BenchmarkProjectToTile
    BenchmarkProjectToTile-16    	   14942	     80458 ns/op	    6672 B/op	     309 allocs/op
    BenchmarkProjectToGeo
    BenchmarkProjectToGeo-16     	   19521	     64411 ns/op	    6672 B/op	     309 allocs/op
    PASS
    

    Stable:

    BenchmarkMarshal
    BenchmarkMarshal-16          	    1363	    817600 ns/op	  411622 B/op	    5354 allocs/op
    BenchmarkUnmarshal
    BenchmarkUnmarshal-16        	    4479	    245967 ns/op	  208905 B/op	    2468 allocs/op
    BenchmarkProjectToTile
    BenchmarkProjectToTile-16    	   15022	     83612 ns/op	    6672 B/op	     309 allocs/op
    BenchmarkProjectToGeo
    BenchmarkProjectToGeo-16     	   19256	     61878 ns/op	    6672 B/op	     309 allocs/op
    PASS
    

    I'm happy to go whatever route you'd prefer here. I understand you may not want to impact the perf since the stability hasn't mattered up to now. I can perhaps add a separate method like MarshalStable?

    Much appreciated!

  • fix removal

    fix removal

    Without that extra cleanup step it was possible to create nodes with nil values and non-nil children in the middle of the tree which later lead to the removal of those orphans

  • Quadtree KNearest not in sorted order

    Quadtree KNearest not in sorted order

    Inconsistent sorting of results slice with the KNearest function. The reduced test case below produces out of order results despite the recent enhancements in #67. Note that I am not passing the optional maxDistance attribute to KNearest.

    Expected result: results slice in closest to farther ordering Actual result: certain slice elements in unexpected ordering

    package main
    
    import (
    	"testing"
    
    	"github.com/paulmach/orb"
    	"github.com/paulmach/orb/geo"
    	"github.com/paulmach/orb/quadtree"
    )
    
    // place implements the orb.Pointer interface so that it may be added to a QuadTree
    type place struct {
    	Id       string // name of the city
    	Location orb.Point
    }
    
    func (p place) Point() orb.Point {
    	return p.Location
    }
    
    var destinations = []place{
    	{"Portland (Oregon)", orb.Point{-122.6784, 45.5152}},
    	{"Sydney", orb.Point{151.2093, -33.8688}},
    	{"Jakarta", orb.Point{106.8456, -6.200000}},
    	{"Tunis", orb.Point{10.181667, 36.806389}},
    	{"Paris", orb.Point{2.3522, 48.8566}},
    }
    
    func TestQuadtreeKnn(t *testing.T) {
    	qt := quadtree.New(orb.Bound{Min: orb.Point{-180, -90}, Max: orb.Point{180, 90}})
    	for _, dest := range destinations {
    		qt.Add(dest)
    	}
    	maxResults := 5
    
    	// for the following cities, find the maxResults nearest neighbours
    	fromCities := []place{
    		{"London", orb.Point{-0.118092, 51.509865}},
    	}
    
    	for _, from := range fromCities {
    		t.Run(from.Id, func(t *testing.T) {
    			t.Logf("%s : %d nearest places to %v \n", from.Id, maxResults, from.Location)
    			results := qt.KNearest(nil, from.Point(), maxResults)
    			prevKm := 0.0
    			for i, dest := range results {
    				p := dest.(place)
    				dKm := geo.DistanceHaversine(from.Location, p.Location) / 1000
    				t.Logf("[%s] at sorted index %d : %s, %.0f km away (%+v)\n", from.Id, i, p.Id, dKm, p.Location)
    				if prevKm > dKm {
    					t.Errorf("FAIL: Out of order results, previous = %.0f km > this = %.0f km", prevKm, dKm)
    				}
    				prevKm = dKm
    			}
    		})
    	}
    }
    
  • Subdivide polygon

    Subdivide polygon

    Hello,

    I'm trying to subdivide a polygon into sub polygons as described in this [post](https://gis.stackexchange.com/a/375130). Has anyone ever archieved a this ?

  • Polygon and line intersection coordinates

    Polygon and line intersection coordinates

    Hi!

    I'd like to know, how to rewrite this example from go.geo readme to use orb library:

    path := geo.NewPath()
    path.Push(geo.NewPoint(0, 0))
    path.Push(geo.NewPoint(1, 1))
    
    line := geo.NewLine(geo.NewPoint(0, 1), geo.NewPoint(1, 0))
    
    // intersects does a simpler check for yes/no
    if path.Intersects(line) {
    	// intersection will return the actual points and places on intersection
    	points, segments := path.Intersection(line)
    
    	for i, _ := range points {
    		log.Printf("Intersection %d at %v with path segment %d", i, points[i], segments[i][0])
    	}
    }
    

    In my case I assume path points as polygon coordinates. Thanks!

  • The resulting MVT is too big (27MB)

    The resulting MVT is too big (27MB)

    Hi,

    I have a large geojson file (500 MB) that i try to load in mapboxgl for performance reasons I needed to convert into vector tiles.

    The issue is that it still return large mvt tiles size (around 27MB) which causes the mapbox to hang and gets laggy.

    Is there a way to limit the number of features that is projected to a tile ?

  • copy the original mvt.Layers for reuse

    copy the original mvt.Layers for reuse

    Hi there,

    I am trying to build a tileserver that reads geojson and serve tiles

    I started by reading the json file:

    geojsonData, err := ioutil.ReadFile("./data/large_data.geojson")
    

    then I unmarshal the file to go object:

    r = map[string]*geojson.FeatureCollection{}
    err = json.Unmarshal(geojsonData, &r)
    
    layers := mvt.NewLayers(r)
    

    when serving the tiles the original values of the layers gets mutated, which force me to read and unmarshal the geojson again,

    I tried to copy layers so I don't modify the original layers, but still changing one changes the other.

    How I can copy the layers by value?

  • Check of overlapping geometries

    Check of overlapping geometries

    Firstly, I want to say thank you for creating such a great package and ecosystem for working with geometries.

    Is there currently a way to determine if two geometries are overlapped? Similar to PostGIS's ST_OVERLAPS function.

Geometry/geography library in Go, DEPRECATED, use ->

go.geo (deprecated) Go.geo is a geometry/geography library in Go. The primary use case is GIS geometry manipulation on the server side vs. in the brow

Jan 2, 2023
S2 geometry library in Go

Overview S2 is a library for spherical geometry that aims to have the same robustness, flexibility, and performance as the best planar geometry librar

Dec 31, 2022
Efficient 2D geometry library for Go.

geometry An efficient 2D geometry library for Go. Features Point, Rect, Line, and Polygon geometry types Operations such as Intersects, Contains, and

Dec 22, 2022
General purpose library for reading, writing and working with OpenStreetMap data

osm This package is a general purpose library for reading, writing and working with OpenStreetMap data in Go (golang). It has the ability to read OSM

Dec 30, 2022
Bidirectional UTM-WGS84 converter for golang :earth_africa: :globe_with_meridians:

UTM Bidirectional UTM-WGS84 converter for golang. It use logic from UTM python version by Tobias Bieniek Usage go get github.com/im7mortal/UTM Conver

May 21, 2022
Go (golang) wrapper for GDAL, the Geospatial Data Abstraction Library

------------- About ------------- The gdal.go package provides a go wrapper for GDAL, the Geospatial Data Abstraction Library. More information about

Dec 24, 2022
OpenStreetMap PBF golang parser

pbf OpenStreetMap PBF golang encoder/decoder A golang based OpenStreetMap PBF encoder/decoder with a handy command line utility, pbf. pbf Command Line

Oct 23, 2022
Go package to quick and easy create json data in geojson format.

#GEOJSON Go package to easy and quick create datastructure which can be serialized to geojson format INSTALLATION $ go get github.com/kpawlik/geojson

Jun 6, 2022
Encoding and decoding GeoJSON <-> Go

go.geojson Go.geojson is a package for encoding and decoding GeoJSON into Go structs. Supports both the json.Marshaler and json.Unmarshaler interfaces

Jan 2, 2023
Package kml provides convenince methods for creating and writing KML documents.

go-kml Package kml provides convenience methods for creating and writing KML documents. Key Features Simple API for building arbitrarily complex KML d

Jul 29, 2022
Package polyline implements a Google Maps Encoding Polyline encoder and decoder.

go-polyline Package polyline implements a Google Maps Encoding Polyline encoder and decoder. Encoding example func ExampleEncodeCoords() { coords :=

Dec 1, 2022
Publish Your GIS Data(Vector Data) to PostGIS and Geoserver
Publish Your GIS Data(Vector Data) to PostGIS and Geoserver

GISManager Publish Your GIS Data(Vector Data) to PostGIS and Geoserver How to install: go get -v github.com/hishamkaram/gismanager Usage: testdata fol

Sep 26, 2022
Real-time Geospatial and Geofencing
Real-time Geospatial and Geofencing

Tile38 is an open source (MIT licensed), in-memory geolocation data store, spatial index, and realtime geofence. It supports a variety of object types

Dec 30, 2022
A library provides spatial data and geometric algorithms

Geoos Our organization spatial-go is officially established! The first open source project Geoos(Using Golang) provides spatial data and geometric alg

Dec 27, 2022
Types and utilities for working with 2d geometry in Golang

orb Package orb defines a set of types for working with 2d geo and planar/projected geometric data in Golang. There are a set of sub-packages that use

Dec 28, 2022
Go types, funcs, and utilities for working with cards, decks, and evaluating poker hands (Holdem, Omaha, Stud, more)

cardrank.io/cardrank Package cardrank.io/cardrank provides a library of types, funcs, and utilities for working with playing cards, decks, and evaluat

Dec 25, 2022
Plugs module to see different types of plug types needed in different countries, and a comparison tool between two countries plug socket types.

plugs Importing the module: go get github.com/matthewboyd/plugs "github.com/matthewboyd/plugs" How to use the module: There are two functions wi

Dec 28, 2021
Package geom implements efficient geometry types for geospatial applications.

go-geom Package geom implements efficient geometry types for geospatial applications. Key features OpenGeo Consortium-style geometries. Support for 2D

Jan 6, 2023
Library providing opanapi3 and Go types for store/validation and transfer of ISO-4217, ISO-3166, and other types.

go-types This library has been created with the purpose to facilitate the store, validation, and transfer of Go ISO-3166/ISO-4217/timezones/emails/URL

Nov 9, 2022
Some Golang types based on builtin. Implements interfaces Value / Scan and MarshalJSON / UnmarshalJSON for simple working with database NULL-values and Base64 encoding / decoding.

gotypes Some simple types based on builtin Golang types that implement interfaces for working with DB (Scan / Value) and JSON (Marshal / Unmarshal). N

Feb 12, 2022