diff --git a/examples/test_tiff/test_tiff.go b/examples/test_tiff/test_tiff.go index 60cd588..9e2de9a 100644 --- a/examples/test_tiff/test_tiff.go +++ b/examples/test_tiff/test_tiff.go @@ -1,8 +1,8 @@ package main import ( - "fmt" "flag" + "fmt" "github.com/lukeroth/gdal" ) @@ -14,15 +14,15 @@ func main() { return } fmt.Printf("Filename: %s\n", filename) - + fmt.Printf("Allocating buffer\n") var buffer [256 * 256]uint8 // buffer := make([]uint8, 256 * 256) - + fmt.Printf("Computing values\n") for x := 0; x < 256; x++ { for y := 0; y < 256; y++ { - loc := x + y * 256 + loc := x + y*256 val := x + y if val >= 256 { val -= 256 @@ -32,7 +32,7 @@ func main() { } fmt.Printf("%d drivers available\n", gdal.GetDriverCount()) - for x:= 0; x < gdal.GetDriverCount(); x++ { + for x := 0; x < gdal.GetDriverCount(); x++ { driver := gdal.GetDriver(x) fmt.Printf("%s: %s\n", driver.ShortName(), driver.LongName()) } @@ -46,7 +46,7 @@ func main() { fmt.Printf("Creating dataset\n") dataset := driver.Create(filename, 256, 256, 1, gdal.Byte, nil) defer dataset.Close() - + fmt.Printf("Creating projection\n") spatialRef := gdal.CreateSpatialReference("") @@ -70,12 +70,12 @@ func main() { fmt.Printf("Reading geotransform:") geoTransform := dataset.GeoTransform() - fmt.Printf("%v, %v, %v, %v, %v, %v\n", + fmt.Printf("%v, %v, %v, %v, %v, %v\n", geoTransform[0], geoTransform[1], geoTransform[2], geoTransform[3], geoTransform[4], geoTransform[5]) fmt.Printf("Reading projection:") wkt := dataset.Projection() fmt.Printf("%s\n", wkt) - - fmt.Printf("End program\n") -} \ No newline at end of file + + fmt.Printf("End program\n") +} diff --git a/gdal.go b/gdal.go index 32651b0..375d122 100644 --- a/gdal.go +++ b/gdal.go @@ -46,7 +46,7 @@ var ( ) // Error handling. The following is bare-bones, and needs to be replaced with something more useful. -func (err _Ctype_CPLErr) Err() error { +func (err CPLErr) Err() error { switch err { case 0: return nil @@ -62,7 +62,7 @@ func (err _Ctype_CPLErr) Err() error { return ErrIllegal } -func (err _Ctype_OGRErr) Err() error { +func (err OGRErr) Err() error { switch err { case 0: return nil @@ -691,9 +691,9 @@ func (object MajorObject) SetMetadataItem(name, value, domain string) { return } -// TODO: Make korrekt class hirerarchy via interfaces +// TODO: Make correct class hirerarchy via interfaces -func (object *RasterBand) SetMetadataItem(name, value, domain string) error { +func (rasterBand *RasterBand) SetMetadataItem(name, value, domain string) error { c_name := C.CString(name) defer C.free(unsafe.Pointer(c_name)) @@ -704,7 +704,7 @@ func (object *RasterBand) SetMetadataItem(name, value, domain string) error { defer C.free(unsafe.Pointer(c_domain)) return C.GDALSetMetadataItem( - C.GDALMajorObjectH(unsafe.Pointer(object.cval)), + C.GDALMajorObjectH(unsafe.Pointer(rasterBand.cval)), c_name, c_value, c_domain, ).Err() } @@ -1412,7 +1412,7 @@ func (rasterBand RasterBand) FlushCache() { } // Compute raster histogram -func (rb RasterBand) Histogram( +func (rasterBand RasterBand) Histogram( min, max float64, buckets int, includeOutOfRange, approxOK int, @@ -1426,7 +1426,7 @@ func (rb RasterBand) Histogram( histogram := make([]C.GUIntBig, buckets) if err := C.GDALGetRasterHistogramEx( - rb.cval, + rasterBand.cval, C.double(min), C.double(max), C.int(buckets), @@ -1443,7 +1443,7 @@ func (rb RasterBand) Histogram( } // Fetch default raster histogram -func (rb RasterBand) DefaultHistogram( +func (rasterBand RasterBand) DefaultHistogram( force int, progress ProgressFunc, data interface{}, @@ -1455,7 +1455,7 @@ func (rb RasterBand) DefaultHistogram( var cHistogram *C.GUIntBig err = C.GDALGetDefaultHistogramEx( - rb.cval, + rasterBand.cval, (*C.double)(&min), (*C.double)(&max), (*C.int)(unsafe.Pointer(&buckets)), diff --git a/go_ogr_wkb.c b/go_ogr_wkb.c new file mode 100644 index 0000000..aaab29a --- /dev/null +++ b/go_ogr_wkb.c @@ -0,0 +1,36 @@ +// Copyright 2019 AirMap Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +#include "go_ogr_wkb.h" + +#include + +#if GDAL_COMPUTE_VERSION(GDAL_VERSION_MAJOR, GDAL_VERSION_MINOR, GDAL_VERSION_PATCH) >= GDAL_COMPUTE_VERSION(2, 3, 0) + +OGRErr go_CreateFromWkb(void* pabyData, OGRSpatialReferenceH hSRS, OGRGeometryH* phGeometry, int nBytes) { + return OGR_G_CreateFromWkb(pabyData, hSRS, phGeometry, nBytes); +} + +OGRErr go_ImportFromWkb(OGRGeometryH hGeom, void* pabyData, int nSize) { + return OGR_G_ImportFromWkb(hGeom, pabyData, nSize); +} + +OGRErr go_ExportToWkb(OGRGeometryH hGeom, OGRwkbByteOrder eOrder, unsigned char* pabyDstBuffer) { + return OGR_G_ExportToWkb(hGeom, eOrder, pabyDstBuffer); +} + +#elif GDAL_COMPUTE_VERSION(GDAL_VERSION_MAJOR, GDAL_VERSION_MINOR, GDAL_VERSION_PATCH) < GDAL_COMPUTE_VERSION(2, 3, 0) + +OGRErr go_CreateFromWkb(void* pabyData, OGRSpatialReferenceH hSRS, OGRGeometryH* phGeometry, int nBytes) { + return OGR_G_CreateFromWkb((unsigned char*)pabyData, hSRS, phGeometry, nBytes); +} + +OGRErr go_ImportFromWkb(OGRGeometryH hGeom, void* pabyData, int nSize) { + return OGR_G_ImportFromWkb(hGeom, (unsigned char*)pabyData, nSize); +} + +OGRErr go_ExportToWkb(OGRGeometryH hGeom, OGRwkbByteOrder eOrder, unsigned char* pabyDstBuffer) { + return OGR_G_ExportToWkb(hGeom, eOrder, pabyDstBuffer); +} + +#endif // GDAL_COMPUTE_VERSION(GDAL_VERSION_MAJOR, GDAL_VERSION_MINOR, GDAL_VERSION_PATCH) >= GDAL_COMPUTE_VERSION(2, 3, 0) diff --git a/go_ogr_wkb.h b/go_ogr_wkb.h new file mode 100644 index 0000000..bc59235 --- /dev/null +++ b/go_ogr_wkb.h @@ -0,0 +1,18 @@ +// Copyright 2019 AirMap Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +#ifndef GO_OGR_WKB_H_ +#define GO_OGR_WKB_H_ + +#include + +// go_CreateFromWkb helps us in handling an API/ABI break introduced by gdal 2.3.0. +OGRErr go_CreateFromWkb(void *pabyData, OGRSpatialReferenceH hSRS, OGRGeometryH* phGeometry, int nBytes); + +// go_CreateFromWkb helps us in handling an API/ABI break introduced by gdal 2.3.0. +OGRErr go_ImportFromWkb(OGRGeometryH hGeom, void* pabyData, int nSize); + +// go_ExportToWkb helps us in handling an API/ABI break introduced by gdal 2.3.0. +OGRErr go_ExportToWkb(OGRGeometryH hGeom, OGRwkbByteOrder eOrder, unsigned char* pabyDstBuffer); + +#endif // GO_OGR_WKB_H_ diff --git a/ogr.go b/ogr.go index 0a0ae37..8c9e492 100644 --- a/ogr.go +++ b/ogr.go @@ -2,6 +2,7 @@ package gdal /* #include "go_gdal.h" +#include "go_ogr_wkb.h" #include "gdal_version.h" #cgo linux pkg-config: gdal @@ -187,10 +188,10 @@ type Geometry struct { //Create a geometry object from its well known binary representation func CreateFromWKB(wkb []uint8, srs SpatialReference, bytes int) (Geometry, error) { - pabyData := (unsafe.Pointer(&wkb[0])) + cString := unsafe.Pointer(&wkb[0]) var newGeom Geometry - return newGeom, C.OGR_G_CreateFromWkb( - pabyData, srs.cval, &newGeom.cval, C.int(bytes), + return newGeom, C.go_CreateFromWkb( + cString, srs.cval, &newGeom.cval, C.int(bytes), ).Err() } @@ -305,15 +306,15 @@ func (geom Geometry) Envelope() Envelope { // Assign a geometry from well known binary data func (geom Geometry) FromWKB(wkb []uint8, bytes int) error { - pabyData := (unsafe.Pointer(&wkb[0])) - return C.OGR_G_ImportFromWkb(geom.cval, pabyData, C.int(bytes)).Err() + cString := unsafe.Pointer(&wkb[0]) + return C.go_ImportFromWkb(geom.cval, cString, C.int(bytes)).Err() } // Convert a geometry to well known binary data func (geom Geometry) ToWKB() ([]uint8, error) { b := make([]uint8, geom.WKBSize()) cString := (*C.uchar)(unsafe.Pointer(&b[0])) - err := C.OGR_G_ExportToWkb(geom.cval, C.OGRwkbByteOrder(C.wkbNDR), cString).Err() + err := C.go_ExportToWkb(geom.cval, C.OGRwkbByteOrder(C.wkbNDR), cString).Err() return b, err } @@ -394,7 +395,9 @@ func (geom Geometry) ToGML_Ex(options []string) string { // Convert a geometry to KML format func (geom Geometry) ToKML() string { val := C.OGR_G_ExportToKML(geom.cval, nil) - return C.GoString(val) + result = C.GoString(val) + C.CPL_Free(unsafe.Pointer(val)) + return result } // Convert a geometry to JSON format @@ -533,7 +536,10 @@ func (geom Geometry) Union(other Geometry) Geometry { return Geometry{newGeom} } -// Unimplemented: UnionCascaded +func (geom Geometry) UnionCascaded() Geometry { + newGeom := C.OGR_G_UnionCascaded(geom.cval) + return Geometry{newGeom} +} // Unimplemented: PointOn Surface (until 2.0) // Return a point guaranteed to lie on the surface @@ -590,6 +596,11 @@ func (geom Geometry) IsEmpty() bool { return val != 0 } +// Test if the geometry is null +func (geom Geometry) IsNull() bool { + return geom.cval == nil +} + // Test if the geometry is valid func (geom Geometry) IsValid() bool { val := C.OGR_G_IsValid(geom.cval) @@ -724,16 +735,18 @@ func (geom Geometry) BuildPolygonFromEdges(autoClose bool, tolerance float64) (G type FieldType int const ( - FT_Integer = FieldType(C.OFTInteger) - FT_IntegerList = FieldType(C.OFTIntegerList) - FT_Real = FieldType(C.OFTReal) - FT_RealList = FieldType(C.OFTRealList) - FT_String = FieldType(C.OFTString) - FT_StringList = FieldType(C.OFTStringList) - FT_Binary = FieldType(C.OFTBinary) - FT_Date = FieldType(C.OFTDate) - FT_Time = FieldType(C.OFTTime) - FT_DateTime = FieldType(C.OFTDateTime) + FT_Integer = FieldType(C.OFTInteger) + FT_IntegerList = FieldType(C.OFTIntegerList) + FT_Real = FieldType(C.OFTReal) + FT_RealList = FieldType(C.OFTRealList) + FT_String = FieldType(C.OFTString) + FT_StringList = FieldType(C.OFTStringList) + FT_Binary = FieldType(C.OFTBinary) + FT_Date = FieldType(C.OFTDate) + FT_Time = FieldType(C.OFTTime) + FT_DateTime = FieldType(C.OFTDateTime) + FT_Integer64 = FieldType(C.OFTInteger64) + FT_Integer64List = FieldType(C.OFTInteger64List) ) type Justification int @@ -1074,6 +1087,12 @@ func (feature Feature) FieldAsInteger(index int) int { return int(val) } +// Fetch field value as 64-bit integer +func (feature Feature) FieldAsInteger64(index int) int { + val := C.OGR_F_GetFieldAsInteger64(feature.cval, C.int(index)) + return int64(val) +} + // Fetch field value as float64 func (feature Feature) FieldAsFloat64(index int) float64 { val := C.OGR_F_GetFieldAsDouble(feature.cval, C.int(index)) @@ -1098,6 +1117,18 @@ func (feature Feature) FieldAsIntegerList(index int) []int { return goSlice } +// Fetch field as list of 64-bit integers +func (feature Feature) FieldAsInteger64List(index int) []int64 { + var count int + cArray := C.OGR_F_GetFieldAsInteger64List(feature.cval, C.int(index), (*C.int)(unsafe.Pointer(&count))) + var goSlice []int64 + header := (*reflect.SliceHeader)(unsafe.Pointer(&goSlice)) + header.Cap = count + header.Len = count + header.Data = uintptr(unsafe.Pointer(cArray)) + return goSlice +} + // Fetch field as list of float64 func (feature Feature) FieldAsFloat64List(index int) []float64 { var count int @@ -1163,6 +1194,11 @@ func (feature Feature) SetFieldInteger(index, value int) { C.OGR_F_SetFieldInteger(feature.cval, C.int(index), C.int(value)) } +// Set field to 64-bit integer value +func (feature Feature) SetFieldInteger64(index int, value int64) { + C.OGR_F_SetFieldInteger64(feature.cval, C.int(index), C.GIntBig(value)) +} + // Set field to float64 value func (feature Feature) SetFieldFloat64(index int, value float64) { C.OGR_F_SetFieldDouble(feature.cval, C.int(index), C.double(value)) @@ -1185,6 +1221,16 @@ func (feature Feature) SetFieldIntegerList(index int, value []int) { ) } +// Set field to list of 64-bit integers +func (feature Feature) SetFieldInteger64List(index int, value []int64) { + C.OGR_F_SetFieldIntegerList( + feature.cval, + C.int(index), + C.int(len(value)), + (*C.int)(unsafe.Pointer(&value[0])), + ) +} + // Set field to list of float64 func (feature Feature) SetFieldFloat64List(index int, value []float64) { C.OGR_F_SetFieldDoubleList( @@ -1282,6 +1328,11 @@ func (feature Feature) SetStyleString(style string) { C.OGR_F_SetStyleStringDirectly(feature.cval, cStyle) } +// Returns true if this contains a null pointer +func (feature Feature) IsNull() bool { + return feature.cval == nil +} + /* -------------------------------------------------------------------- */ /* Layer functions */ /* -------------------------------------------------------------------- */