Created
May 15, 2015 15:17
-
-
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)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
https://gist.github.com/wroge/b7cd3c9dda9973b7085a10b09360ea00