Skip to content

Instantly share code, notes, and snippets.

@schoenobates
Created May 15, 2015 15:17
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save schoenobates/f6ca293eadfe2b7b4157 to your computer and use it in GitHub Desktop.
Save schoenobates/f6ca293eadfe2b7b4157 to your computer and use it in GitHub Desktop.
Using Golang with Proj4 to convert between OSGB and WGS84 (both to and from)
package main
/*
#cgo LDFLAGS: -lproj
#include <string.h>
#include <proj_api.h>
*/
import "C"
import (
"fmt"
"os"
"strconv"
"strings"
"unsafe"
)
type Projection string
// Proj4 defs
const (
EPSG_27700 Projection = "+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000 +y_0=-100000 +ellps=airy +datum=OSGB36 +units=m +no_defs +nadgrids=/usr/local/share/proj/OSTN02_NTv2.gsb"
EPSG_4326 Projection = "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs"
)
// radians <-> degrees
const (
radians float64 = 0.017453292519943295
degrees float64 = 57.29577951308232
)
// Holds a LatLng pair
type LatLng struct {
Lat, Lng float64
}
func (ll *LatLng) ToDegrees() *LatLng {
return &LatLng{
Lat: ll.Lat * degrees,
Lng: ll.Lng * degrees,
}
}
func (ll *LatLng) ToRadians() *LatLng {
return &LatLng{
Lat: ll.Lat * radians,
Lng: ll.Lng * radians,
}
}
type Proj4Error struct {
retval int
}
func (e *Proj4Error) Error() string {
return fmt.Sprintf("Proj4 Error: %d", e.retval)
}
// Converts the given LatLng coordinate pair from the source projection to destination projection
func Convert(ll *LatLng, Source, Destination Projection) (*LatLng, error) {
fromProj := C.CString(string(Source))
toProj := C.CString(string(Destination))
defer func() {
C.free(unsafe.Pointer(fromProj))
C.free(unsafe.Pointer(toProj))
}()
fpj := C.pj_init_plus(fromProj)
tpj := C.pj_init_plus(toProj)
lat := C.double(ll.Lat)
lng := C.double(ll.Lng)
retval := int(C.pj_transform(fpj, tpj, 1, 1, &lng, &lat, nil))
C.pj_free(fpj)
C.pj_free(tpj)
if retval != 0 {
return nil, &Proj4Error{retval}
}
return &LatLng{
Lat: float64(lat),
Lng: float64(lng),
}, nil
}
func main() {
if len(os.Args) != 4 {
fmt.Println("usage: osgb [from|to] <x> <y>\n\n\tUsed to convert between WGS84 and OSGB using Proj4 in Go.")
os.Exit(0)
}
cmd := strings.ToLower(os.Args[1])
x, err := strconv.ParseFloat(os.Args[2], 64)
if err != nil {
fmt.Printf("Failed to parse X: %s", err)
os.Exit(-1)
}
y, err := strconv.ParseFloat(os.Args[3], 64)
if err != nil {
fmt.Printf("Failed to parse Y: %s", err)
os.Exit(-1)
}
latlng := &LatLng{y, x}
var ll *LatLng
if cmd == "from" {
ll, err = Convert(latlng, EPSG_27700, EPSG_4326)
} else {
ll, err = Convert(latlng.ToRadians(), EPSG_4326, EPSG_27700)
}
if err != nil {
fmt.Println(err)
if pe, ok := err.(*Proj4Error); ok {
os.Exit(pe.retval)
}
}
//ll = ll.ToDegrees()
if cmd == "from" {
ll = ll.ToDegrees()
}
fmt.Printf("%.15f %.15f", ll.Lng, ll.Lat)
}
@schoenobates
Copy link
Author

In order to use this code, you'll need to install proj4 and OSTN02_NTv2 file located here:

http://www.ordnancesurvey.co.uk/business-and-government/help-and-support/navigation-technology/os-net/formats-for-developers.html

@wroge
Copy link

wroge commented Oct 10, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment