diff --git a/mbgl/README.md b/mbgl/README.md index 43a8d35..bfbff6e 100644 --- a/mbgl/README.md +++ b/mbgl/README.md @@ -23,4 +23,6 @@ This directory contains direct go bindings against the Mapbox GL Native C++ API. * in the higher level package, `runtime.SetFinalizer` is used for memory management, note that this cannot be done for classes (which are aliased as empty structs) as: > It is not guaranteed that a finalizer will run if the size of *obj is zero bytes. -> https://golang.org/pkg/runtime/#SetFinalizer \ No newline at end of file +> https://golang.org/pkg/runtime/#SetFinalizer + +* after calling `(T).Destruct()` make sure to not reuse the variable, this will result in strange errors; another `(T).Destruct()` call might yeild something like "freed block must be allocated with malloc". \ No newline at end of file diff --git a/mbgl/camera_options.go b/mbgl/camera_options.go index 4372e85..25013b3 100644 --- a/mbgl/camera_options.go +++ b/mbgl/camera_options.go @@ -6,8 +6,10 @@ import "C" */ import "C" -type EdgeInsets struct { - ptr *C.MbglEdgeInsets +type EdgeInsets C.MbglEdgeInsets + +func (ei *EdgeInsets) edgeInsets() *C.MbglEdgeInsets { + return (*C.MbglEdgeInsets)(ei) } func NewEdgeInsets(top, left, bottom, right float64) *EdgeInsets { @@ -18,11 +20,11 @@ func NewEdgeInsets(top, left, bottom, right float64) *EdgeInsets { C.double(right), ) - return &EdgeInsets{ptr:ptr} + return (*EdgeInsets)(ptr) } func (ei *EdgeInsets) Destruct() { - C.mbgl_edge_insets_destruct(ei.ptr) + C.mbgl_edge_insets_destruct(ei.edgeInsets()) } type Point struct { @@ -69,12 +71,12 @@ func (opt *CameraOptions) update() { // todo (@ear7h): change structs to wrapped types var center *C.MbglLatLng if opt.Center != nil { - center = opt.Center.ptr + center = opt.Center.latLng() } var padding *C.MbglEdgeInsets if opt.Padding != nil { - padding = opt.Padding.ptr + padding = opt.Padding.edgeInsets() } if opt.ptr == nil { diff --git a/mbgl/default_file_source.go b/mbgl/default_file_source.go index 79db915..44cfbd0 100644 --- a/mbgl/default_file_source.go +++ b/mbgl/default_file_source.go @@ -6,25 +6,25 @@ package mbgl */ import "C" -type DefaultFileSource struct { - ptr *C.MbglDefaultFileSource +type DefaultFileSource C.MbglDefaultFileSource + +func (fs *DefaultFileSource) defaultFileSource() *C.MbglDefaultFileSource { + return (*C.MbglDefaultFileSource)(fs) } +// This instantiates a new file source which can handle online and offline sources. It will create a chache file func NewDefaultFileSource(cachePath, assetRoot string, maxCache *uint64) *DefaultFileSource { ptr := C.mbgl_default_file_source_new(C.CString(cachePath), C.CString(assetRoot), (*C.uint64_t)(maxCache)) - return &DefaultFileSource{ - ptr: ptr, - } + return (*DefaultFileSource)(ptr) } -func (fs DefaultFileSource) fileSource() *C.MbglFileSource { - return (*C.MbglFileSource)(fs.ptr) +func (fs *DefaultFileSource) fileSource() *C.MbglFileSource { + return (*C.MbglFileSource)(fs.defaultFileSource()) } func (fs *DefaultFileSource) Destruct() { - C.mbgl_default_file_source_destruct(fs.ptr) - fs.ptr = nil + C.mbgl_default_file_source_destruct(fs.defaultFileSource()) } \ No newline at end of file diff --git a/mbgl/lat_lng.go b/mbgl/lat_lng.go index fa42437..a790b90 100644 --- a/mbgl/lat_lng.go +++ b/mbgl/lat_lng.go @@ -7,31 +7,29 @@ import "C" import "github.com/go-spatial/geom/slippy" //TODO (@ear7h): use github.com/go-spatial/geom type -type LatLng struct { - ptr *C.MbglLatLng -} +type LatLng C.MbglLatLng func NewLatLng(lat, lng float64) *LatLng { ptr := C.mbgl_lat_lng_new(C.double(lat), C.double(lng)) - return &LatLng{ptr:ptr} + return (*LatLng)(ptr) +} + +func (ll *LatLng) latLng() *C.MbglLatLng { + return (*C.MbglLatLng)(ll) } func (ll *LatLng) Destruct() { - C.mbgl_lat_lng_destruct(ll.ptr) - ll.ptr = nil + C.mbgl_lat_lng_destruct(ll.latLng()) } // bounds - -type LatLngBounds struct { - ptr *C.MbglLatLngBounds -} +type LatLngBounds C.MbglLatLngBounds func NewLatLngBounds(a, b *LatLng) *LatLngBounds { - ptr := C.mbgl_lat_lng_bounds_hull(a.ptr, b.ptr) - return &LatLngBounds{ptr:ptr} + ptr := C.mbgl_lat_lng_bounds_hull(a.latLng(), b.latLng()) + return (*LatLngBounds)(ptr) } func NewLatLngBoundsFromTile(tile *slippy.Tile) *LatLngBounds { @@ -48,6 +46,10 @@ func NewLatLngBoundsFromTile(tile *slippy.Tile) *LatLngBounds { return ret } +func (bb *LatLngBounds) latLngBounds() *C.MbglLatLngBounds { + return (*C.MbglLatLngBounds)(bb) +} + func (bb *LatLngBounds) Destruct() { - C.mbgl_lat_lng_bounds_destruct(bb.ptr) + C.mbgl_lat_lng_bounds_destruct(bb.latLngBounds()) } \ No newline at end of file diff --git a/mbgl/map_snapshotter.go b/mbgl/map_snapshotter.go index 7ce9c2a..fdbb546 100644 --- a/mbgl/map_snapshotter.go +++ b/mbgl/map_snapshotter.go @@ -12,9 +12,7 @@ import ( "fmt" ) -type MapSnapshotter struct { - ptr *C.MbglMapSnapshotter -} +type MapSnapshotter C.MbglMapSnapshotter func NewMapSnapshotter(src FileSource, @@ -38,7 +36,7 @@ func NewMapSnapshotter(src FileSource, var _region *C.MbglLatLngBounds if region != nil { - _region = region.ptr + _region = region.latLngBounds() } var _cacheDir *C.char @@ -57,43 +55,48 @@ func NewMapSnapshotter(src FileSource, _region, _cacheDir) - return &MapSnapshotter{ptr:ptr} + return (*MapSnapshotter)(ptr) +} + +func (ms *MapSnapshotter) mapSnapshotter() *C.MbglMapSnapshotter { + return (*C.MbglMapSnapshotter)(ms) } -func (ms MapSnapshotter) Snapshot() *PremultipliedImage { - ptr := C.mbgl_map_snapshotter_snapshot(ms.ptr) - return &PremultipliedImage{ptr:ptr} +func (ms *MapSnapshotter) Snapshot() *PremultipliedImage { + ptr := C.mbgl_map_snapshotter_snapshot(ms.mapSnapshotter()) + return (*PremultipliedImage)(ptr) } -func (ms MapSnapshotter) SetCameraOptions(camOpts CameraOptions) { - C.mbgl_map_snapshotter_set_camera_options(ms.ptr, camOpts.cPtr()) +func (ms *MapSnapshotter) SetCameraOptions(camOpts CameraOptions) { + C.mbgl_map_snapshotter_set_camera_options(ms.mapSnapshotter(), camOpts.cPtr()) } -func (ms MapSnapshotter) SetRegion(region *LatLngBounds) { - C.mbgl_map_snapshotter_set_region(ms.ptr, region.ptr) +func (ms *MapSnapshotter) SetRegion(region *LatLngBounds) { + C.mbgl_map_snapshotter_set_region(ms.mapSnapshotter(), region.latLngBounds()) } -func (ms MapSnapshotter) SetStyleURL(style string) { +func (ms *MapSnapshotter) SetStyleURL(style string) { fmt.Println("setting style, ", style) - C.mbgl_map_snapshotter_set_style_url(ms.ptr, C.CString(style)) + C.mbgl_map_snapshotter_set_style_url(ms.mapSnapshotter(), C.CString(style)) fmt.Println("style set") } -func (ms MapSnapshotter) SetSize(size Size) { - C.mbgl_map_snapshotter_set_size(ms.ptr, size.cSize()) +func (ms *MapSnapshotter) SetSize(size Size) { + C.mbgl_map_snapshotter_set_size(ms.mapSnapshotter(), size.cSize()) } func (ms *MapSnapshotter) Destruct() { - C.mbgl_map_snapshotter_destruct(ms.ptr) - ms.ptr = nil + C.mbgl_map_snapshotter_destruct(ms.mapSnapshotter()) } -type PremultipliedImage struct { - ptr *C.MbglPremultipliedImage +type PremultipliedImage C.MbglPremultipliedImage + +func (im *PremultipliedImage) premultipliedImage() *C.MbglPremultipliedImage { + return (*C.MbglPremultipliedImage)(im) } -func (im PremultipliedImage) Image() image.Image { - raw := C.mbgl_premultiplied_image_raw(im.ptr) +func (im *PremultipliedImage) Image() image.Image { + raw := C.mbgl_premultiplied_image_raw(im.premultipliedImage()) bytes := int(raw.width) * int(raw.height) * 4 @@ -106,8 +109,7 @@ func (im PremultipliedImage) Image() image.Image { } func (im *PremultipliedImage) Destruct() { - C.mbgl_premultiplied_image_destruct(im.ptr) - im.ptr = nil + C.mbgl_premultiplied_image_destruct(im.premultipliedImage()) } type img struct { diff --git a/mbgl/map_snapshotter_test.go b/mbgl/map_snapshotter_test.go index d21b17d..61c7523 100644 --- a/mbgl/map_snapshotter_test.go +++ b/mbgl/map_snapshotter_test.go @@ -8,6 +8,7 @@ import ( "github.com/go-spatial/geom/slippy" "path/filepath" "strings" + "github.com/arolek/p" ) func TestNewMapSnapshotter(t *testing.T) { @@ -38,7 +39,7 @@ func TestNewMapSnapshotter(t *testing.T) { testcases := map[string]tcase{ "1": { - src: NewDefaultFileSource("", "", nil), + src: NewDefaultFileSource("", "", p.Uint64(0)), sched: NewThreadPool(4), style: "https://osm.tegola.io/maps/osm/style.json", size: Size{Width: 100, Height: 100}, @@ -94,7 +95,7 @@ func TestSnapshotterSnapshot(t *testing.T) { testcases := map[string]tcase{ "1": { ms: NewMapSnapshotter( - NewDefaultFileSource("", "", nil), + NewDefaultFileSource("", "", p.Uint64(0)), tpool, "https://osm.tegola.io/maps/osm/style.json", Size{Height: 100, Width: 100}, @@ -122,7 +123,7 @@ func TestSnapshotterSetCamOpts(t *testing.T) { SchedulerSetCurrent(tpool) ms := NewMapSnapshotter( - NewDefaultFileSource("", "", nil), + NewDefaultFileSource("", "", p.Uint64(0)), tpool, "https://osm.tegola.io/maps/osm/style.json", Size{Height: 100, Width: 100}, @@ -171,7 +172,7 @@ func TestSnapshotterSetRegion(t *testing.T) { SchedulerSetCurrent(tpool) ms := NewMapSnapshotter( - NewDefaultFileSource("","", nil), + NewDefaultFileSource("","", p.Uint64(0)), tpool, "https://osm.tegola.io/maps/osm/style.json", Size{Height: 100, Width: 100}, diff --git a/mbgl/scheduler.go b/mbgl/scheduler.go index 1fadc49..502cce0 100644 --- a/mbgl/scheduler.go +++ b/mbgl/scheduler.go @@ -12,16 +12,14 @@ type Scheduler interface { } // Satisfies the schduler inteface -type scheduler struct { - ptr *C.MbglScheduler -} +type scheduler C.MbglScheduler func (s *scheduler) scheduler() *C.MbglScheduler { - return s.ptr + return (*C.MbglScheduler)(s) } func (s *scheduler) Destruct() { - C.mbgl_scheduler_destruct(s.ptr) + C.mbgl_scheduler_destruct(s.scheduler()) } func SchedulerGetCurrent() Scheduler { @@ -30,9 +28,7 @@ func SchedulerGetCurrent() Scheduler { return nil } - return &scheduler{ - ptr: ptr, - } + return (*scheduler)(ptr) } func SchedulerSetCurrent(sched Scheduler) { diff --git a/mbgl/thread_pool.go b/mbgl/thread_pool.go index 5ba814b..98836db 100644 --- a/mbgl/thread_pool.go +++ b/mbgl/thread_pool.go @@ -6,28 +6,23 @@ package mbgl */ import "C" -type ThreadPool struct { - ptr *C.MbglThreadPool -} +type ThreadPool C.MbglThreadPool func NewThreadPool(threads int) (*ThreadPool) { ptr := C.mbgl_thread_pool_new(C.int(threads)) - return &ThreadPool{ - ptr: ptr, - } + return (*ThreadPool)(ptr) } -func (t ThreadPool) threadPool() *C.MbglThreadPool { - return t.ptr +func (t *ThreadPool) threadPool() *C.MbglThreadPool { + return (*C.MbglThreadPool)(t) } // Scheduler is a prarent class -func (t ThreadPool) scheduler() *C.MbglScheduler { - return (*C.MbglScheduler)(t.ptr) +func (t *ThreadPool) scheduler() *C.MbglScheduler { + return (*C.MbglScheduler)(t) } func (t *ThreadPool) Destruct() { - C.mbgl_thread_pool_destruct(t.ptr) - t.ptr = nil + C.mbgl_thread_pool_destruct(t.threadPool()) } diff --git a/snapshotter.go b/snapshotter.go index fd97243..95bea8d 100644 --- a/snapshotter.go +++ b/snapshotter.go @@ -8,6 +8,7 @@ import ( "github.com/go-spatial/geom" "github.com/go-spatial/go-mbgl/mbgl" "github.com/go-spatial/geom/slippy" + "github.com/arolek/p" ) // This will set the size of the mbgl::ThreadPool @@ -38,27 +39,30 @@ func (s snapshotter) destruct() { // High level function for taking a single snappshot. This simply creates a new snapshotter and uses it. -func Snapshot(style string, ext *geom.Extent, size image.Point) image.Image { - return NewSnapshotter(style).Snapshot(ext, size) +func Snapshot(style string, ext *geom.Extent, size image.Point, pixelRatio float32) image.Image { + return NewSnapshotter(style, pixelRatio).Snapshot(ext, size) } // This creates an instance of a Snapshotter with the specified style. // Note: this high level implementation is thread safe, but performance might be better to lower the DefaultThreadPoolSize and use multiple snapshotters // TODO(@ear7h): write benchmarks -func NewSnapshotter(style string) Snapshotter { - src := mbgl.NewDefaultFileSource("", "", nil) - runtime.SetFinalizer(src, (*mbgl.DefaultFileSource).Destruct) +func NewSnapshotter(style string, pixelRatio float32) Snapshotter { + src := mbgl.NewDefaultFileSource("", "", p.Uint64(0)) tpool := mbgl.NewThreadPool(DefaultThreadPoolSize) mbgl.SchedulerSetCurrent(tpool) size := mbgl.Size{Width: 100, Height: 100} + if pixelRatio == 0 { + pixelRatio = 1.0 + } + snap := mbgl.NewMapSnapshotter(src, tpool, style, size, - 1.0, + pixelRatio, nil, nil, nil) @@ -69,6 +73,8 @@ func NewSnapshotter(style string) Snapshotter { size: size, } + // finalizer has to be on Go composite objecte because mbgl + // types are pointers to empty structs as far as go knows runtime.SetFinalizer(ret, (*snapshotter).destruct) return ret diff --git a/snapshotter_test.go b/snapshotter_test.go index 0265022..16911af 100644 --- a/snapshotter_test.go +++ b/snapshotter_test.go @@ -17,10 +17,11 @@ func TestSnapshot(t *testing.T) { src string ext *geom.Extent size image.Point + ratio float32 } fn := func(tc tcase, t *testing.T) { - img := Snapshot(tc.src, tc.ext, tc.size) + img := Snapshot(tc.src, tc.ext, tc.size, tc.ratio) fname := os.DevNull if evar := os.Getenv("MBGL_TEST_OUT_DIR"); evar != "" { @@ -45,7 +46,13 @@ func TestSnapshot(t *testing.T) { exts := make(map[string]*geom.Extent) - exts["1"] = slippy.NewTileLatLon(12, 33, 117, 0, geom.WebMercator).Extent(geom.WGS84) + tile := slippy.NewTileLatLon(12, 33, 117, 0, geom.WebMercator) + + exts["1"] = tile.Extent(geom.WGS84) + + z, x, y := tile.ZXY() + tile = slippy.NewTile(z, x + 1, y, 0) + exts["2"] = tile.Extent(geom.WGS84) fmt.Println(exts["1"]) @@ -54,6 +61,36 @@ func TestSnapshot(t *testing.T) { src: "https://osm.tegola.io/maps/osm/style.json", ext: exts["1"], size: image.Pt(1000, 1000), + ratio: 1.0, + }, + "2": { + src: "https://osm.tegola.io/maps/osm/style.json", + ext: exts["1"], + size: image.Pt(1000, 1000), + ratio: 2.0, + }, + "3": { + src: "https://osm.tegola.io/maps/osm/style.json", + ext: exts["1"], + size: image.Pt(1000, 1000), + ratio: 0.5, + }, + "4": { + src: "https://osm.tegola.io/maps/osm/style.json", + ext: exts["1"], + size: image.Pt(500, 500), + ratio: 2.0, + }, + "5": { + src: "https://osm.tegola.io/maps/osm/style.json", + ext: exts["1"], + size: image.Pt(500, 500), + ratio: 0.5, + }, + "small": { + src: "https://osm.tegola.io/maps/osm/style.json", + ext: exts["1"], + size: image.Pt(1, 1), }, }