150 lines
2.8 KiB
Go
150 lines
2.8 KiB
Go
package ogr
|
|
|
|
/*
|
|
#cgo LDFLAGS: -lgdal
|
|
#include "ogr_api.h"
|
|
#include "cpl_error.h"
|
|
#include "cpl_conv.h"
|
|
*/
|
|
import "C"
|
|
import (
|
|
"fmt"
|
|
"goposm/geom/geos"
|
|
"strings"
|
|
"unsafe"
|
|
)
|
|
|
|
func init() {
|
|
C.OGRRegisterAll()
|
|
}
|
|
|
|
type DataSource struct {
|
|
v C.OGRDataSourceH
|
|
}
|
|
|
|
type Layer struct {
|
|
v C.OGRLayerH
|
|
}
|
|
type OgrError struct {
|
|
message string
|
|
}
|
|
|
|
func (e *OgrError) Error() string {
|
|
return e.message
|
|
}
|
|
|
|
func lastOgrError(fallback string) error {
|
|
msg := C.CPLGetLastErrorMsg()
|
|
if msg == nil {
|
|
return &OgrError{fallback}
|
|
}
|
|
str := C.GoString(msg)
|
|
if str == "" {
|
|
return &OgrError{fallback}
|
|
}
|
|
return &OgrError{str}
|
|
}
|
|
|
|
func Open(name string) (*DataSource, error) {
|
|
namec := C.CString(name)
|
|
defer C.free(unsafe.Pointer(namec))
|
|
ds := C.OGROpen(namec, 0, nil)
|
|
if ds == nil {
|
|
return nil, lastOgrError("failed to open")
|
|
}
|
|
return &DataSource{ds}, nil
|
|
}
|
|
|
|
func (ds *DataSource) Layer() (*Layer, error) {
|
|
layer := C.OGR_DS_GetLayer(ds.v, 0)
|
|
if layer == nil {
|
|
return nil, lastOgrError("failed to get layer 0")
|
|
}
|
|
return &Layer{layer}, nil
|
|
}
|
|
|
|
func (ds *DataSource) Query(query string) (*Layer, error) {
|
|
// create select query if it is only a where statement
|
|
if !strings.HasPrefix(strings.ToLower(query), "select") {
|
|
layer, err := ds.Layer()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
layerDef := C.OGR_L_GetLayerDefn(layer.v)
|
|
name := C.OGR_FD_GetName(layerDef)
|
|
query = fmt.Sprintf("SELECT * FROM %s WHERE %s", C.GoString(name), query)
|
|
}
|
|
queryc := C.CString(query)
|
|
defer C.free(unsafe.Pointer(queryc))
|
|
layer := C.OGR_DS_ExecuteSQL(ds.v, queryc, nil, nil)
|
|
if layer == nil {
|
|
return nil, lastOgrError("unable to execute query '" + query + "'")
|
|
}
|
|
return &Layer{layer}, nil
|
|
}
|
|
|
|
func (layer *Layer) Wkts() chan string {
|
|
wkts := make(chan string)
|
|
|
|
go func() {
|
|
defer close(wkts)
|
|
|
|
C.OGR_L_ResetReading(layer.v)
|
|
for {
|
|
feature := C.OGR_L_GetNextFeature(layer.v)
|
|
if feature == nil {
|
|
break
|
|
}
|
|
geom := C.OGR_F_GetGeometryRef(feature)
|
|
var res *C.char
|
|
C.OGR_G_ExportToWkt(geom, &res)
|
|
wkts <- C.GoString(res)
|
|
C.CPLFree(unsafe.Pointer(res))
|
|
C.OGR_F_Destroy(feature)
|
|
|
|
}
|
|
}()
|
|
|
|
return wkts
|
|
}
|
|
|
|
func (layer *Layer) Wkbs() chan []byte {
|
|
wkbs := make(chan []byte)
|
|
|
|
go func() {
|
|
defer close(wkbs)
|
|
|
|
C.OGR_L_ResetReading(layer.v)
|
|
for {
|
|
feature := C.OGR_L_GetNextFeature(layer.v)
|
|
if feature == nil {
|
|
break
|
|
}
|
|
geom := C.OGR_F_GetGeometryRef(feature)
|
|
size := C.OGR_G_WkbSize(geom)
|
|
buf := make([]byte, size)
|
|
C.OGR_G_ExportToWkb(geom, C.wkbNDR, (*C.uchar)(&buf[0]))
|
|
wkbs <- buf
|
|
C.OGR_F_Destroy(feature)
|
|
}
|
|
}()
|
|
return wkbs
|
|
}
|
|
|
|
func (layer *Layer) Geoms() chan *geos.Geom {
|
|
geoms := make(chan *geos.Geom)
|
|
|
|
go func() {
|
|
defer close(geoms)
|
|
g := geos.NewGeos()
|
|
defer g.Finish()
|
|
|
|
wkbs := layer.Wkbs()
|
|
for wkb := range wkbs {
|
|
geom := g.FromWkb(wkb)
|
|
geoms <- geom
|
|
}
|
|
}()
|
|
return geoms
|
|
}
|