geo

package module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 27, 2026 License: AGPL-3.0 Imports: 11 Imported by: 1

README

geo 🌎

GeoJSON primitives for Go and MongoDB. This package provides four geographic value types — Position, Point, Polygon, and Address — each with JSON and BSON marshalling that follows the GeoJSON specification (RFC 7946). Address additionally models a human-readable postal address with optional geocoded coordinates.

The types are designed to be useful at their zero value and to round-trip cleanly through JSON, BSON, and mapof.Any maps.

The types

  • Position — a single longitude, latitude[, altitude] coordinate. The building block; Point embeds it. Marshals as a GeoJSON coordinate array ([lon, lat]), not an object.
  • Point — a GeoJSON Point object ({"type":"Point","coordinates":[lon,lat]}).
  • Polygon — a GeoJSON Polygon: a single ring of Position values.
  • Address — a postal address (schema.org/PostalAddress-style) plus optional latitude/longitude, time zone, and Plus Code.

What matters here

  • Coordinate order is longitude, latitude — per the GeoJSON spec, not the lat, lon order humans usually say aloud. NewPosition, NewPoint, and the coordinates arrays all take longitude first. The LatLon() / LonLat() helpers exist precisely because both orders are needed depending on the consumer.

  • String forms must preserve precision — never route coordinates through rosetta/convert.String. As of rosetta v0.27.0, convert.String rounds floats to two decimal places, which silently corrupts coordinates (~1 km of error). Position.String() uses strconv.FormatFloat(f, 'f', -1, 64) (minimal lossless digits) for this reason. formatCoordinatePair (backing LonLat/LatLon on Point and Address) instead uses fixed 10-decimal precision — a deliberately different format, so don't consolidate the two.

  • Address map keys must match the struct tags. MarshalMap/UnmarshalMap key by the AddressProperty* constants, while JSON/BSON key by the struct tags in address.go. These two key sets must stay identical or data crossing between the map path and the JSON/BSON path is silently dropped — the historical "pluscode" vs "plusCode" mismatch did exactly that. When adding an Address field, update the constant, the struct tag, MarshalMap, UnmarshalMap, and the accessors together.

  • AddressSchema() intentionally omits timezone and plusCode. They are derived/geocoded fields, not user-editable form inputs, so they're absent from the rosetta schema even though MarshalMap emits them. This is deliberate, not an oversight.

  • SetString("formatted", …) has a side effect: it clears all geocoded fields when the value actually changes. The formatted address and the parsed/geocoded fields are kept consistent — a new formatted value invalidates the old geocode.

  • Point/Polygon marshal to null when zero. MarshalJSON returns null for a zero value (works with omitzero, not omitempty). Round-tripping a zero Point through JSON yields a zero Point, not an error.

Accessor pattern

Address follows the rosetta-style Get*/Get*OK convention: GetString/GetFloat return a bare value (zero on miss); GetStringOK/GetFloatOK add a boolean that reports whether the property name was recognized.

References

Documentation

Overview

Package geo provides geographic value types — Position, Point, Polygon, and Address — along with JSON and BSON (GeoJSON) marshalling for each.

Position, Point, and Polygon follow the GeoJSON specification (https://datatracker.ietf.org/doc/html/rfc7946), while Address models a human-readable postal address with optional geocoded coordinates.

Index

Constants

View Source
const (
	// AddressPropertyName is the human-readable name of the address.
	AddressPropertyName = "name"

	// AddressPropertyFormatted is the full, unparsed value of the address.
	AddressPropertyFormatted = "formatted"

	// AddressPropertyStreet1 is the first line of the street address.
	AddressPropertyStreet1 = "street1"

	// AddressPropertyStreet2 is the second line of the street address.
	AddressPropertyStreet2 = "street2"

	// AddressPropertyLocality is the city or town of the address.
	AddressPropertyLocality = "locality"

	// AddressPropertyRegion is the state or province of the address.
	AddressPropertyRegion = "region"

	// AddressPropertyPostalCode is the postal code of the address.
	AddressPropertyPostalCode = "postalCode"

	// AddressPropertyCountry is the country of the address.
	AddressPropertyCountry = "country"

	// AddressPropertyLongitude is the longitude of the address.
	AddressPropertyLongitude = "longitude"

	// AddressPropertyLatitude is the latitude of the address.
	AddressPropertyLatitude = "latitude"

	// AddressPropertyTimezone is the IANA time zone name of the address.
	AddressPropertyTimezone = "timezone"

	// AddressPropertyPlusCode is the Google Plus Code of the address.
	AddressPropertyPlusCode = "plusCode"
)

Property names used to read, write, and marshal the fields of an Address.

View Source
const (
	// PropertyType is the GeoJSON "type" property.
	PropertyType = "type"

	// PropertyCoordinates is the GeoJSON "coordinates" property.
	PropertyCoordinates = "coordinates"
)

GeoJSON property names used in marshalled output.

View Source
const (
	// PropertyTypePoint is the GeoJSON type value for a Point.
	PropertyTypePoint = "Point"

	// PropertyTypePolygon is the GeoJSON type value for a Polygon.
	PropertyTypePolygon = "Polygon"
)

GeoJSON "type" values supported by this package.

Variables

This section is empty.

Functions

func AddressSchema added in v0.0.2

func AddressSchema() schema.Element

AddressSchema returns the rosetta schema that describes an Address.

Types

type Address added in v0.0.2

type Address struct {
	Name       string  `json:"name"        bson:"name,omitempty"`       // Human-readable name of the address
	Formatted  string  `json:"formatted"   bson:"formatted,omitempty"`  // Full, unparsed value of the address
	Street1    string  `json:"street1"     bson:"street1,omitempty"`    // Parsed street address line 1 of the address
	Street2    string  `json:"street2"     bson:"street2,omitempty"`    // Parsed street address line 2 of the address
	Locality   string  `json:"locality"    bson:"locality,omitempty"`   // Parsed city or town of the address
	Region     string  `json:"region"      bson:"region,omitempty"`     // Parsed state or province of the address
	PostalCode string  `json:"postalCode"  bson:"postalCode,omitempty"` // Parsed postal code of the address
	Country    string  `json:"country"     bson:"country,omitempty"`    // Parsed country of the address
	PlusCode   string  `json:"plusCode"    bson:"plusCode,omitempty"`   // PlusCode for this location https://maps.google.com/pluscodes/
	Timezone   string  `json:"timezone"    bson:"timezone,omitempty"`   // Time zone in tzdatabase format (https://en.wikipedia.org/wiki/Tz_database)
	Latitude   float64 `json:"latitude"    bson:"latitude,omitempty"`   // Latitude of the address
	Longitude  float64 `json:"longitude"   bson:"longitude,omitempty"`  // Longitude of the address
}

Address represents a physical address on the planet It maps to https://www.w3.org/TR/activitystreams-vocabulary/#dfn-address and uses https://schema.org/PostalAddress to match Mobilizion

func NewAddress added in v0.0.2

func NewAddress() Address

NewAddress returns an empty Address.

func (Address) GeoJSON added in v0.0.2

func (address Address) GeoJSON() mapof.Any

GeoJSON returns this Address as a GeoJSON Point object. https://www.mongodb.com/docs/manual/reference/geojson/

func (Address) GeoPoint added in v0.0.2

func (address Address) GeoPoint() Point

GeoPoint returns a Point representation of this address

func (Address) GetFloat added in v0.0.2

func (address Address) GetFloat(name string) float64

GetFloat returns the named property as a float64, or 0 if it is not a float property.

func (Address) GetFloatOK added in v0.1.0

func (address Address) GetFloatOK(name string) (float64, bool)

GetFloatOK returns the named property as a float64, and a boolean that is TRUE when the property name is recognized ("latitude" or "longitude").

func (Address) GetString added in v0.0.3

func (address Address) GetString(name string) string

GetString returns the named property as a string, or "" if it is not a string property.

func (Address) GetStringOK added in v0.0.2

func (address Address) GetStringOK(name string) (string, bool)

GetStringOK returns the named property as a string, and a boolean that is TRUE when the property name is recognized.

func (Address) HasAddress added in v0.0.2

func (address Address) HasAddress() bool

HasAddress returns TRUE if this Address has ANY street address information

func (Address) HasGeocode added in v0.0.2

func (address Address) HasGeocode() bool

HasGeocode returns TRUE if this Address has ANY Lat/Long information

func (Address) IsZero added in v0.0.2

func (address Address) IsZero() bool

IsZero returns TRUE if this Address has no coordinates and no formatted value.

func (Address) JSONLD added in v0.0.2

func (address Address) JSONLD() mapof.Any

JSONLD returns a JSON-LD representation of this object

func (Address) LatLon added in v0.0.3

func (address Address) LatLon() string

LatLon returns the coordinates as a "latitude,longitude" string.

func (Address) LonLat added in v0.0.3

func (address Address) LonLat() string

LonLat returns the coordinates as a "longitude,latitude" string.

func (Address) MarshalMap added in v0.0.2

func (address Address) MarshalMap() mapof.Any

MarshalMap returns this Address as a mapof.Any keyed by its property names.

func (Address) NotZero added in v0.0.2

func (address Address) NotZero() bool

NotZero returns TRUE if this Address is not Zero.

func (*Address) Reset added in v0.0.2

func (address *Address) Reset()

Reset clears all geocoding information from this Address

func (*Address) SetFloat added in v0.0.2

func (address *Address) SetFloat(name string, value float64) bool

SetFloat sets the "latitude" or "longitude" property and returns TRUE if the property name is writable.

func (*Address) SetPoint added in v0.0.2

func (address *Address) SetPoint(point Point)

SetPoint copies the longitude and latitude from the given Point into this Address.

func (*Address) SetString added in v0.0.2

func (address *Address) SetString(name string, value string) bool

SetString sets the "name" or "formatted" property and returns TRUE if the property name is writable. Changing "formatted" resets any geocoded fields.

func (*Address) UnmarshalMap added in v0.0.2

func (address *Address) UnmarshalMap(value mapof.Any) error

UnmarshalMap populates this address with the properties in the `value` map

type GeoJSONPoint

type GeoJSONPoint struct {
	Type        string    `json:"type"        bson:"type"`        // This should always be "Point"
	Coordinates []float64 `json:"coordinates" bson:"coordinates"` // Whatevs
}

GeoJSONPoint represents the "strict" format for a Point in GeoJSON

type GeoJSONPolygon

type GeoJSONPolygon struct {
	Type        string        `json:"type"        bson:"type"`        // this should always be "Polygon"
	Coordinates [][][]float64 `json:"coordinates" bson:"coordinates"` // ick. Thanks IETF.
}

GeoJSONPolygon represents the "strict" format for a Polygon in GeoJSON. is is used here to simplify conversion to/from serialization formats

type Point

type Point struct {
	Position
}

Point represents a GeoJSON "Point" object https://datatracker.ietf.org/doc/html/rfc7946#section-3.1.2

func NewPoint

func NewPoint(longitude float64, latitude float64) Point

NewPoint returns a Point at the given longitude and latitude (no altitude).

func NewPointWithAltitude

func NewPointWithAltitude(longitude float64, latitude float64, altitude float64) Point

NewPointWithAltitude returns a Point at the given longitude, latitude, and altitude.

func (Point) GeoJSON

func (point Point) GeoJSON() map[string]any

GeoJSON returns this Point as a GeoJSON object (a "type"/"coordinates" map).

func (Point) LatLon added in v0.0.3

func (point Point) LatLon() string

LatLon returns the coordinates as a "latitude,longitude" string.

func (Point) LonLat added in v0.0.3

func (point Point) LonLat() string

LonLat returns the coordinates as a "longitude,latitude" string.

func (Point) MarshalBSON

func (point Point) MarshalBSON() ([]byte, error)

MarshalBSON is a custom BSON marshaller that serializes this Point into a GeoJSON object.

func (Point) MarshalJSON

func (point Point) MarshalJSON() ([]byte, error)

MarshalJSON is a custom json.Marshaller that returns this Point as a GeoJSON object. This marshaller works with `omitzero` but not `omitempty`

func (Point) MarshalStruct

func (point Point) MarshalStruct() GeoJSONPoint

MarshalStruct returns this Point as a strongly-typed GeoJSONPoint.

func (*Point) UnmarshalBSON

func (point *Point) UnmarshalBSON(data []byte) error

UnmarshalBSON is a custom BSON unmarshaller that deserializes a GeoJSON object into this Point structure.

func (*Point) UnmarshalJSON

func (point *Point) UnmarshalJSON(data []byte) error

UnmarshalJSON is a custom json.Unmarshaller that parses a GeoJSON object into this Point object.

func (*Point) UnmarshalMap

func (point *Point) UnmarshalMap(data mapof.Any) error

UnmarshalMap populates this Point using the values from the provided data. If the data does not fit the correct GeoJSON format, then this method returns an error

type Polygon

type Polygon struct {
	Coordinates sliceof.Object[Position]
}

Polygon represents a GeoJSON "Polygon" object https://datatracker.ietf.org/doc/html/rfc7946#section-3.1.2

func NewPolygon

func NewPolygon(coordinates ...Position) Polygon

NewPolygon returns a Polygon made up of the given positions.

func NewPolygonFromString

func NewPolygonFromString(data string) Polygon

NewPolygonFromString parses a comma-delimited list of coordinates ("lon,lat,lon,lat,...") into a Polygon. Unparseable values and an unpaired trailing coordinate are silently dropped.

func (Polygon) GeoJSON

func (polygon Polygon) GeoJSON() map[string]any

GeoJSON returns a GeoJSON representation of this Polygon

func (Polygon) IsZero

func (polygon Polygon) IsZero() bool

IsZero returns TRUE if this Polygon has no coordinates.

func (Polygon) MarshalBSON

func (polygon Polygon) MarshalBSON() ([]byte, error)

MarshalBSON is a custom BSON marshaller that serializes this Polygon into a GeoJSON object.

func (Polygon) MarshalJSON

func (polygon Polygon) MarshalJSON() ([]byte, error)

MarshalJSON is a custom json.Marshaller that returns this Polygon as a GeoJSON object.

func (Polygon) MarshalSlice

func (polygon Polygon) MarshalSlice() [][]float64

MarshalSlice returns (a slice of (a slice of floats)), which is the standard way of representing a GeoJSON polygon

func (Polygon) MarshalStruct

func (polygon Polygon) MarshalStruct() GeoJSONPolygon

MarshalStruct returns this Polygon as a strongly-typed GeoJSONPolygon.

func (Polygon) NotZero

func (polygon Polygon) NotZero() bool

NotZero returns TRUE if this Polygon has at least one coordinate.

func (Polygon) String

func (polygon Polygon) String() string

String returns the coordinates as a comma-delimited "lon,lat,lon,lat,..." string.

func (*Polygon) UnmarshalBSON

func (polygon *Polygon) UnmarshalBSON(data []byte) error

UnmarshalBSON is a custom BSON unmarshaller that deserializes a GeoJSON object into this Polygon structure.

func (*Polygon) UnmarshalJSON

func (polygon *Polygon) UnmarshalJSON(data []byte) error

UnmarshalJSON is a custom json.Unmarshaller that parses a GeoJSON object into this Polygon object.

func (*Polygon) UnmarshalStruct

func (polygon *Polygon) UnmarshalStruct(data GeoJSONPolygon) error

UnmarshalStruct populates this Polygon from a strongly-typed GeoJSONPolygon, which must contain exactly one ring of coordinates.

type Position

type Position struct {
	Longitude float64
	Latitude  float64
	Altitude  float64
}

Position represents a Longitude/Latitude pair https://datatracker.ietf.org/doc/html/rfc7946#section-3.1.1

func NewPosition

func NewPosition(longitude float64, latitude float64) Position

NewPosition returns a Position at the given longitude and latitude (no altitude).

func NewPositionWithAltitude

func NewPositionWithAltitude(longitude float64, latitude float64, altitude float64) Position

NewPositionWithAltitude returns a Position at the given longitude, latitude, and altitude.

func (Position) IsZero

func (position Position) IsZero() bool

IsZero returns TRUE if this is a Zero position

func (Position) MarshalBSONValue added in v0.1.0

func (position Position) MarshalBSONValue() (bsontype.Type, []byte, error)

MarshalBSONValue is a custom BSON marshaller that serializes this Position into a GeoJSON coordinate pair. It implements bson.ValueMarshaler (rather than bson.Marshaler) because a coordinate pair is a BSON array, not a document.

func (Position) MarshalJSON

func (position Position) MarshalJSON() ([]byte, error)

MarshalJSON is a custom JSON marshaller that serializes this Position into a GeoJSON coordinate pair

func (Position) MarshalSlice

func (position Position) MarshalSlice() []float64

MarshalSlice returns a longitude/latitude coordinate pair

func (Position) NotZero

func (position Position) NotZero() bool

NotZero returns TRUE if this Position is not Zero

func (Position) String

func (position Position) String() string

String returns a string representation of this coordinate pair

func (*Position) UnmarshalBSONValue added in v0.1.0

func (position *Position) UnmarshalBSONValue(dataType bsontype.Type, data []byte) error

UnmarshalBSONValue is a custom BSON unmarshaller that deserializes a BSON / GeoJSON coordinate pair into this Position structure. It implements bson.ValueUnmarshaler to match MarshalBSONValue's array encoding.

func (*Position) UnmarshalJSON

func (position *Position) UnmarshalJSON(data []byte) error

UnmarshalJSON is a custom JSON unmarshaller that deserializes a GeoJSON coordinate pair into this Position structure.

func (*Position) UnmarshalSlice

func (position *Position) UnmarshalSlice(coordinates sliceof.Float) error

UnmarshalSlice populates this Position from a coordinate slice of length 2 (longitude, latitude) or length 3 (longitude, latitude, altitude).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL