Merge branch 'master' of bitbucket.org:olt/goposm
commit
d7ce2053d2
|
@ -0,0 +1,49 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
_ "github.com/bmizerany/pq"
|
||||
"goposm/element"
|
||||
"goposm/geom"
|
||||
"log"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.SetFlags(log.LstdFlags | log.Lshortfile)
|
||||
db, err := sql.Open("postgres", "user=olt host=/var/run/postgresql dbname=osm sslmode=disable")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec("DROP TABLE IF EXISTS test")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
_, err = db.Exec("CREATE TABLE IF NOT EXISTS test (val VARCHAR);")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
_, err = db.Query("SELECT AddGeometryColumn('test', 'geom', 3857, 'LINESTRING', 2);")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
size := 16
|
||||
nodes := make([]element.Node, size)
|
||||
for i := 0; i < size; i++ {
|
||||
nodes[i] = element.Node{Lat: 0, Long: float64(i)}
|
||||
}
|
||||
wkb := geom.LineString(nodes)
|
||||
|
||||
stmt, err := db.Prepare("INSERT INTO test (val, geom) VALUES ($1, ST_SetSRID(ST_GeomFromWKB($2), 3857));")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = stmt.Exec("test", wkb)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
}
|
40
geom/geom.go
40
geom/geom.go
|
@ -1,64 +1,64 @@
|
|||
package geom
|
||||
|
||||
import (
|
||||
"gogeos"
|
||||
"goposm/element"
|
||||
"goposm/geom/geos"
|
||||
)
|
||||
|
||||
func PointWKB(geos *gogeos.GEOS, node element.Node) ([]byte, error) {
|
||||
coordSeq, err := geos.CreateCoordSeq(1, 2)
|
||||
func PointWKB(g *geos.GEOS, node element.Node) ([]byte, error) {
|
||||
coordSeq, err := g.CreateCoordSeq(1, 2)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// coordSeq inherited by LineString
|
||||
coordSeq.SetXY(geos, 0, nd.Long, nd.Lat)
|
||||
geom, err := coordSeq.AsPoint(geos)
|
||||
coordSeq.SetXY(g, 0, node.Long, node.Lat)
|
||||
geom, err := coordSeq.AsPoint(g)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer geos.Destroy(geom)
|
||||
return geos.AsWKB(geom)
|
||||
defer g.Destroy(geom)
|
||||
return g.AsWKB(geom)
|
||||
}
|
||||
|
||||
func LineStringWKB(geos *gogeos.GEOS, nodes []element.Node) ([]byte, error) {
|
||||
coordSeq, err := geos.CreateCoordSeq(uint32(len(nodes)), 2)
|
||||
func LineStringWKB(g *geos.GEOS, nodes []element.Node) ([]byte, error) {
|
||||
coordSeq, err := g.CreateCoordSeq(uint32(len(nodes)), 2)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// coordSeq inherited by LineString
|
||||
for i, nd := range nodes {
|
||||
coordSeq.SetXY(geos, uint32(i), nd.Long, nd.Lat)
|
||||
coordSeq.SetXY(g, uint32(i), nd.Long, nd.Lat)
|
||||
}
|
||||
geom, err := coordSeq.AsLineString(geos)
|
||||
geom, err := coordSeq.AsLineString(g)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer geos.Destroy(geom)
|
||||
return geos.AsWKB(geom)
|
||||
defer g.Destroy(geom)
|
||||
return g.AsWKB(geom)
|
||||
}
|
||||
|
||||
func PolygonWKB(geos *gogeos.GEOS, nodes []element.Node) ([]byte, error) {
|
||||
coordSeq, err := geos.CreateCoordSeq(uint32(len(nodes)), 2)
|
||||
func PolygonWKB(g *geos.GEOS, nodes []element.Node) ([]byte, error) {
|
||||
coordSeq, err := g.CreateCoordSeq(uint32(len(nodes)), 2)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// coordSeq inherited by LineString, no destroy
|
||||
for i, nd := range nodes {
|
||||
err := coordSeq.SetXY(geos, uint32(i), nd.Long, nd.Lat)
|
||||
err := coordSeq.SetXY(g, uint32(i), nd.Long, nd.Lat)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
geom, err := coordSeq.AsLinearRing(geos)
|
||||
geom, err := coordSeq.AsLinearRing(g)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// geom inherited by Polygon, no destroy
|
||||
geom = geos.CreatePolygon(geom, nil)
|
||||
geom = g.CreatePolygon(geom, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer geos.Destroy(geom)
|
||||
defer g.Destroy(geom)
|
||||
|
||||
return geos.AsWKB(geom)
|
||||
return g.AsWKB(geom)
|
||||
}
|
||||
|
|
|
@ -2,8 +2,8 @@ package geom
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"gogeos"
|
||||
"goposm/element"
|
||||
"goposm/geom/geos"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
@ -11,9 +11,9 @@ func TestLineString(t *testing.T) {
|
|||
nodes := make([]element.Node, 2)
|
||||
nodes[0] = element.Node{Lat: 0, Long: 0}
|
||||
nodes[1] = element.Node{Lat: 0, Long: 10}
|
||||
geos := gogeos.NewGEOS()
|
||||
defer geos.Finish()
|
||||
wkt, err := LineStringWKB(geos, nodes)
|
||||
g := geos.NewGEOS()
|
||||
defer g.Finish()
|
||||
wkt, err := LineStringWKB(g, nodes)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -29,9 +29,9 @@ func TestPolygon(t *testing.T) {
|
|||
element.Node{Lat: 10, Long: 10},
|
||||
element.Node{Lat: 0, Long: 0},
|
||||
}
|
||||
geos := gogeos.NewGEOS()
|
||||
defer geos.Finish()
|
||||
wkt, err := PolygonWKB(geos, nodes)
|
||||
g := geos.NewGEOS()
|
||||
defer g.Finish()
|
||||
wkt, err := PolygonWKB(g, nodes)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -47,9 +47,9 @@ func TestPolygonNotClosed(t *testing.T) {
|
|||
element.Node{Lat: 0, Long: 10},
|
||||
element.Node{Lat: 10, Long: 10},
|
||||
}
|
||||
geos := gogeos.NewGEOS()
|
||||
defer geos.Finish()
|
||||
_, err := PolygonWKB(geos, nodes)
|
||||
g := geos.NewGEOS()
|
||||
defer g.Finish()
|
||||
_, err := PolygonWKB(g, nodes)
|
||||
if err == nil {
|
||||
t.Fatal("no error")
|
||||
}
|
||||
|
@ -61,10 +61,10 @@ func BenchmarkLineString(b *testing.B) {
|
|||
for i := 0; i < size; i++ {
|
||||
nodes[i] = element.Node{Lat: 0, Long: float64(i)}
|
||||
}
|
||||
geos := gogeos.NewGEOS()
|
||||
defer geos.Finish()
|
||||
g := geos.NewGEOS()
|
||||
defer g.Finish()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
LineStringWKB(geos, nodes)
|
||||
LineStringWKB(g, nodes)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,157 @@
|
|||
package geos
|
||||
|
||||
/*
|
||||
#cgo LDFLAGS: -lgeos_c
|
||||
#include "geos_c.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
extern void goDebug(char *msg);
|
||||
extern void debug_wrap(const char *fmt, ...);
|
||||
extern GEOSContextHandle_t initGEOS_r_debug();
|
||||
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
//export goDebug
|
||||
func goDebug(msg *C.char) {
|
||||
fmt.Println(C.GoString(msg))
|
||||
}
|
||||
|
||||
type GEOS struct {
|
||||
v C.GEOSContextHandle_t
|
||||
}
|
||||
|
||||
type Geom struct {
|
||||
v *C.GEOSGeometry
|
||||
}
|
||||
|
||||
type CreateError string
|
||||
type Error string
|
||||
|
||||
func (e Error) Error() string {
|
||||
return string(e)
|
||||
}
|
||||
|
||||
func (e CreateError) Error() string {
|
||||
return string(e)
|
||||
}
|
||||
|
||||
func NewGEOS() *GEOS {
|
||||
geos := &GEOS{}
|
||||
geos.v = C.initGEOS_r_debug()
|
||||
return geos
|
||||
}
|
||||
|
||||
func (this *GEOS) Finish() {
|
||||
if this.v != nil {
|
||||
C.finishGEOS_r(this.v)
|
||||
this.v = nil
|
||||
}
|
||||
}
|
||||
|
||||
type CoordSeq struct {
|
||||
v *C.GEOSCoordSequence
|
||||
}
|
||||
|
||||
func (this *GEOS) CreateCoordSeq(size, dim uint32) (*CoordSeq, error) {
|
||||
result := C.GEOSCoordSeq_create_r(this.v, C.uint(size), C.uint(dim))
|
||||
if result == nil {
|
||||
return nil, CreateError("could not create CoordSeq")
|
||||
}
|
||||
return &CoordSeq{result}, nil
|
||||
}
|
||||
|
||||
func (this *CoordSeq) SetXY(handle *GEOS, i uint32, x, y float64) error {
|
||||
if C.GEOSCoordSeq_setX_r(handle.v, this.v, C.uint(i), C.double(x)) == 0 {
|
||||
return Error("unable to SetY")
|
||||
}
|
||||
if C.GEOSCoordSeq_setY_r(handle.v, this.v, C.uint(i), C.double(y)) == 0 {
|
||||
return Error("unable to SetX")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *CoordSeq) AsPoint(handle *GEOS) (*Geom, error) {
|
||||
geom := C.GEOSGeom_createPoint_r(handle.v, this.v)
|
||||
if geom == nil {
|
||||
return nil, CreateError("unable to create Point")
|
||||
}
|
||||
return &Geom{geom}, nil
|
||||
}
|
||||
|
||||
func (this *CoordSeq) AsLineString(handle *GEOS) (*Geom, error) {
|
||||
geom := C.GEOSGeom_createLineString_r(handle.v, this.v)
|
||||
if geom == nil {
|
||||
return nil, CreateError("unable to create LineString")
|
||||
}
|
||||
return &Geom{geom}, nil
|
||||
}
|
||||
|
||||
func (this *CoordSeq) AsLinearRing(handle *GEOS) (*Geom, error) {
|
||||
ring := C.GEOSGeom_createLinearRing_r(handle.v, this.v)
|
||||
if ring == nil {
|
||||
return nil, CreateError("unable to create LinearRing")
|
||||
}
|
||||
return &Geom{ring}, nil
|
||||
}
|
||||
|
||||
func (this *GEOS) CreatePolygon(shell *Geom, holes []*Geom) *Geom {
|
||||
if len(holes) > 0 {
|
||||
panic("holes not implemented")
|
||||
}
|
||||
polygon := C.GEOSGeom_createPolygon_r(this.v, shell.v, nil, 0)
|
||||
if polygon == nil {
|
||||
return nil
|
||||
}
|
||||
return &Geom{polygon}
|
||||
}
|
||||
|
||||
func (this *GEOS) GeomFromWKT(wkt string) (geom *Geom) {
|
||||
wktC := C.CString(wkt)
|
||||
defer C.free(unsafe.Pointer(wktC))
|
||||
return &Geom{C.GEOSGeomFromWKT_r(this.v, wktC)}
|
||||
}
|
||||
|
||||
func (this *GEOS) Buffer(geom *Geom, size float64) *Geom {
|
||||
return &Geom{C.GEOSBuffer_r(this.v, geom.v, C.double(size), 50)}
|
||||
}
|
||||
|
||||
func (this *GEOS) AsWKT(geom *Geom) string {
|
||||
return C.GoString(C.GEOSGeomToWKT_r(this.v, geom.v))
|
||||
}
|
||||
func (this *GEOS) AsWKB(geom *Geom) ([]byte, error) {
|
||||
var size C.size_t
|
||||
buf, err := C.GEOSGeomToWKB_buf_r(this.v, geom.v, &size)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return C.GoBytes(unsafe.Pointer(buf), C.int(size)), nil
|
||||
}
|
||||
|
||||
func (this *GEOS) Area(geom *Geom) float64 {
|
||||
var area C.double
|
||||
C.GEOSArea_r(this.v, geom.v, &area)
|
||||
return float64(area)
|
||||
}
|
||||
|
||||
func (this *GEOS) Destroy(geom *Geom) {
|
||||
if geom.v != nil {
|
||||
C.GEOSGeom_destroy_r(this.v, geom.v)
|
||||
geom.v = nil
|
||||
} else {
|
||||
panic("double free?")
|
||||
}
|
||||
}
|
||||
func (this *GEOS) DestroyCoordSeq(coordSeq *CoordSeq) {
|
||||
if coordSeq.v != nil {
|
||||
C.GEOSCoordSeq_destroy_r(this.v, coordSeq.v)
|
||||
coordSeq.v = nil
|
||||
} else {
|
||||
panic("double free?")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package geos
|
||||
|
||||
import "testing"
|
||||
import "math"
|
||||
|
||||
func TestFoo(t *testing.T) {
|
||||
if x := Foo(); math.Abs(x-3.1415) > 0.01 {
|
||||
t.Errorf("Buffer is not 3.1415: %f", x)
|
||||
}
|
||||
geos := NewGEOS()
|
||||
BufferBench(geos)
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package geos
|
||||
|
||||
/*
|
||||
#cgo LDFLAGS: -lgeos_c
|
||||
#include "geos_c.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
extern void goDebug(char *msg);
|
||||
|
||||
void debug_wrap(const char *fmt, ...) {
|
||||
va_list a_list;
|
||||
va_start(a_list, fmt);
|
||||
|
||||
char buf[100];
|
||||
vsnprintf(buf, sizeof(buf), fmt, a_list);
|
||||
va_end(a_list);
|
||||
goDebug((char *)&buf);
|
||||
}
|
||||
|
||||
GEOSContextHandle_t initGEOS_r_debug() {
|
||||
return initGEOS_r(debug_wrap, debug_wrap);
|
||||
}
|
||||
*/
|
||||
import "C"
|
Loading…
Reference in New Issue