orb

repository·master·Indexed 22 days ago

https://github.com/paulmach/orb

A Go library for handling 2D geographic and planar geometric data. It provides high-performance types and sub-packages for GeoJSON, Mapbox Vector Tiles (MVT), WKB/EWKB, and spatial algorithms including clipping (via orb/clip and smartclip) and simplification.

Tokens
17.3K
Snippets
86
Records
102
Agent score
77%

What's inside orb

  1. Overview of the orb package

    master
    The orb package provides a set of types for working with 2D geographic (geo) and planar/projected geometric data in Go. It is designed to be idiomatic, allowing the use of built-in functions like make, append, len, and slice notation. The core of the library is a set of base types that implement a shared Geometry interface, enabling various sub-packages to perform operations like clipping, simplification, and spatial indexing.
  2. Work with Web Mercator map tiles using orb/maptile

    master

    The maptile package provides types and methods for working with Web Mercator map tiles. A tile is represented by the Tile struct, which consists of X and Y coordinates and a Z (Zoom) level.

    Key capabilities include:

    • Creating tiles from longitude/latitude points.
    • Creating tiles from quadkeys.
    • Navigating tile hierarchies using helper methods like Parent(), Children(), and Siblings().
    type Tile struct {
        X, Y uint32
        Z    Zoom
    }
    
    type Zoom uint32
  3. Use orb/planar for Euclidean geometry calculations

    master
    The orb/planar package provides methods for performing geometric calculations that assume a planar or Euclidean context. While the core orb package defines generic 2D geometries, calculations like area, distance, and length depend on the projection (e.g., lon/lat vs. flat plane). Use orb/planar when your coordinates are in a flat, Cartesian coordinate system where Euclidean math is appropriate.
  4. Encode and decode WKT data with encoding/wkt

    master

    The encoding/wkt package allows you to convert between orb.Geometry objects and Well-Known Text (WKT) string representations.

    Use MarshalString to convert any orb.Geometry into its WKT string format.

    Use Unmarshal to parse a WKT string into a generic orb.Geometry. If you know the specific geometry type beforehand, you can use type-specific unmarshal functions for more direct results.

    // Encoding
    // MarshalString(orb.Geometry) string
    
    // Decoding
    // Unmarshal(string) (orb.Geometry, error)
  5. Encode and decode GeoJSON with orb/geojson

    master

    The orb/geojson package provides tools to encode and decode GeoJSON into Go structs using orb geometries. It supports the standard json.Marshaler and json.Unmarshaler interfaces, as well as BSON interfaces for direct use with MongoDB.

    By default, feature properties are handled as map[string]any, but you can use generics to define custom property types.

  6. Handling Feature IDs during MVT marshaling

    master

    MVT uses uint64 for feature IDs, while GeoJSON IDs can be any string or number. During marshaling:

    • The library attempts to convert geojson.Feature.ID to a positive integer.
    • If the ID is a string, it attempts to parse it.
    • If the ID is a negative number, it is omitted.
    • If the ID is a positive decimal, it is truncated.

    During unmarshaling, IDs are converted to float64 to maintain consistency with how the encoding/json package handles numbers.

  7. MySQL geometry compatibility

    master
    The package supports scanning directly from MySQL geometry columns. MySQL typically prefixes WKB data with a 4-byte SRID. If the data is not valid WKB, encoding/wkb will automatically attempt to strip the first 4 bytes and retry the decode.
  8. Encoding GeoJSON Geometry Collections

    master

    When encoding GeoJSON GeometryCollections into MVT, the collections are flattened. Each geometry within the collection is encoded as an individual feature.

    Note: This process causes the original "collection" grouping information to be lost in the resulting MVT, and the output may contain more features than the input GeoJSON.

  9. How the Geometry interface works

    master

    All base types implement the orb.Geometry interface. This allows sub-packages to accept a generic Geometry type and apply the correct algorithm based on the underlying type's dimensions (e.g., 1D for LineString or 2D for Polygon).

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

    Example of polymorphic usage with the clip sub-package:

    l := clip.Geometry(bound, geom)
  10. MVT Version 1 vs. Version 2

    master

    There is no difference in the data format between MVT v1 and v2. The distinction lies in geometry quality:

    • Version 2 requires geometries to be "simple/clean" (e.g., non-self-intersecting lines and polygons with correct winding order).
    • Version 1 is the default for this library because it does not perform automatic geometry validation or cleanup.

    If you are certain your geometries are clean, you can manually set the Version field on a Layer to 2.

  11. Use Generic Properties for type-safe GeoJSON

    master

    Using Go generics, you can define a custom struct for feature properties. This allows for type-safe access to properties without manual type assertions or using the MustX helpers. Use geojson.FeatureCollectionOf[T] and geojson.FeatureOf[T] to work with these typed collections.

    type MyProperties struct {
      Name string `json:"name"`
      Age  int    `json:"age"`
    }
    
    fc := geojson.FeatureCollectionOf[MyProperties]{}
    fc.Append(
      &geojson.FeatureOf[MyProperties]{
        Geometry: orb.Point{1, 2},
        Properties: MyProperties{Name: "Alice", Age: 30},
      },
    )
    
    // Unmarshalling into typed collections
    fc2 := geojson.FeatureCollectionOf[MyProperties]{}
    err := json.Unmarshal(rawJSON, &fc2)
    
    fc2.Features[0].Properties.Name // == "Alice"
  12. Handle extra members in Feature and FeatureCollection

    master

    If your GeoJSON contains fields outside the standard specification (e.g., custom metadata like generator or timestamp), these are captured in the ExtraMembers map. When marshalling, these extra members are included in the base object.

    rawJSON := []byte(`
      { "type": "FeatureCollection",
        "generator": "myapp",
        "timestamp": "2020-06-15T01:02:03Z",
        "features": [
          { "type": "Feature",
            "geometry": {"type": "Point", "coordinates": [102.0, 0.5]},
            "properties": {"prop0": "value0"}
          }
        ]
      }`)
    
    fc, _ := geojson.UnmarshalFeatureCollection(rawJSON)
    
    fc.ExtraMembers["generator"] // == "myApp"
    fc.ExtraMembers["timestamp"] // == "2020-06-15T01:02:03Z"