Merge branch 'master' of bitbucket.org:olt/goposm

master
Oliver Tonnhofer 2013-05-07 07:51:58 +02:00
commit d7ce2053d2
6 changed files with 277 additions and 33 deletions

49
db/postgis.go Normal file
View File

@ -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)
}
}

View File

@ -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)
}

View File

@ -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)
}
}

157
geom/geos/geos.go Normal file
View File

@ -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?")
}
}

12
geom/geos/geos_test.go Normal file
View File

@ -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)
}

26
geom/geos/geos_wrap.go Normal file
View File

@ -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"