Skip to content

Instantly share code, notes, and snippets.

@ldx
Created November 1, 2024 16:28
Show Gist options
  • Save ldx/5f41d49203552d156e16ecb4315ea9f9 to your computer and use it in GitHub Desktop.
Save ldx/5f41d49203552d156e16ecb4315ea9f9 to your computer and use it in GitHub Desktop.
Transform geojson data different coordinate reference systems in Go using go-geom and go-proj
package main
import (
"encoding/json"
"fmt"
"github.com/twpayne/go-geom"
"github.com/twpayne/go-geom/encoding/geojson"
"github.com/twpayne/go-proj/v10"
)
const outCRS = "EPSG:4326"
var data = `{
"type": "FeatureCollection",
"crs": {
"type": "name",
"properties": {
"name": "EPSG:3857"
}
},
"features": [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [0, 0]
}
},
{
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [
[4e6, -2e6],
[8e6, 2e6]
]
}
},
{
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [
[4e6, 2e6],
[8e6, -2e6]
]
}
},
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[-5e6, -1e6],
[-3e6, -1e6],
[-4e6, 1e6],
[-5e6, -1e6]
]
]
}
},
{
"type": "Feature",
"geometry": {
"type": "MultiLineString",
"coordinates": [
[
[-1e6, -7.5e5],
[-1e6, 7.5e5]
],
[
[1e6, -7.5e5],
[1e6, 7.5e5]
],
[
[-7.5e5, -1e6],
[7.5e5, -1e6]
],
[
[-7.5e5, 1e6],
[7.5e5, 1e6]
]
]
}
},
{
"type": "Feature",
"geometry": {
"type": "MultiPolygon",
"coordinates": [
[
[
[-5e6, 6e6],
[-3e6, 6e6],
[-3e6, 8e6],
[-5e6, 8e6],
[-5e6, 6e6]
]
],
[
[
[-2e6, 6e6],
[0, 6e6],
[0, 8e6],
[-2e6, 8e6],
[-2e6, 6e6]
]
],
[
[
[1e6, 6e6],
[3e6, 6e6],
[3e6, 8e6],
[1e6, 8e6],
[1e6, 6e6]
]
]
]
}
},
{
"type": "Feature",
"geometry": {
"type": "GeometryCollection",
"geometries": [
{
"type": "LineString",
"coordinates": [
[-5e6, -5e6],
[0, -5e6]
]
},
{
"type": "Point",
"coordinates": [4e6, -5e6]
},
{
"type": "Polygon",
"coordinates": [
[
[1e6, -6e6],
[3e6, -6e6],
[2e6, -4e6],
[1e6, -6e6]
]
]
}
]
}
}
]
}`
type Properties struct {
Name string `json:"name"`
}
type CRS struct {
Type string `json:"type"`
Properties Properties
}
type FeatureCollection struct {
Type string `json:"type"`
CRS CRS `json:"crs"`
Features []geojson.Feature `json:"features"`
}
func transform(g geom.T, pj *proj.PJ) {
switch g.(type) {
case *geom.Point, *geom.LineString, *geom.LinearRing, *geom.Polygon, *geom.MultiPoint, *geom.MultiLineString, *geom.MultiPolygon:
geom.TransformInPlace(g, func(c geom.Coord) {
coords, err := pj.Forward(proj.Coord{c[0], c[1]})
if err != nil {
panic(err)
}
c[0], c[1] = coords.X(), coords.Y()
})
case *geom.GeometryCollection:
gc := g.(*geom.GeometryCollection)
for _, g := range gc.Geoms() {
transform(g, pj)
}
default:
panic("unsupported geometry type")
}
}
func main() {
var fc FeatureCollection
err := json.Unmarshal([]byte(data), &fc)
pj, err := proj.NewCRSToCRS(fc.CRS.Properties.Name, outCRS, nil)
if err != nil {
panic(err)
}
for _, f := range fc.Features {
transform(f.Geometry, pj)
}
fc.CRS.Properties.Name = outCRS
out, err := json.Marshal(fc)
if err != nil {
panic(err)
}
fmt.Println(string(out))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment