Skip to content

Commit 5f62a08

Browse files
authored
Exposing Experimental PolygonToCells and Updating to Master (#68)
* Exposing Containment Options For PolygonToCells * Adding Experimental PolygonToCells Features, Updating to Master, and Test changing module path update test path trying this? adding CellsToMultiPolygon fixing bad rebase thing updating h3 clean up updating h3 missed a file adjusting to new api updating to entire new h3 experimental api linting clean up
1 parent 0b255e8 commit 5f62a08

File tree

2 files changed

+127
-0
lines changed

2 files changed

+127
-0
lines changed

h3.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ package h3
2525
#include <stdlib.h>
2626
#include <h3_h3api.h>
2727
#include <h3_h3Index.h>
28+
#include <h3_polygon.h>
29+
#include <h3_polyfill.h>
2830
*/
2931
import "C"
3032

@@ -66,6 +68,13 @@ const (
6668

6769
DegsToRads = math.Pi / 180.0
6870
RadsToDegs = 180.0 / math.Pi
71+
72+
// PolygonToCells containment modes
73+
ContainmentCenter ContainmentMode = C.CONTAINMENT_CENTER // Cell center is contained in the shape
74+
ContainmentFull ContainmentMode = C.CONTAINMENT_FULL // Cell is fully contained in the shape
75+
ContainmentOverlapping ContainmentMode = C.CONTAINMENT_OVERLAPPING // Cell overlaps the shape at any point
76+
ContainmentOverlappingBbox ContainmentMode = C.CONTAINMENT_OVERLAPPING_BBOX // Cell bounding box overlaps shape
77+
ContainmentInvalid ContainmentMode = C.CONTAINMENT_INVALID // This mode is invalid and should not be used
6978
)
7079

7180
// Error codes.
@@ -137,6 +146,9 @@ type (
137146
GeoLoop GeoLoop
138147
Holes []GeoLoop
139148
}
149+
150+
// ContainmentMode is an int for specifying PolygonToCell containment behavior.
151+
ContainmentMode C.uint32_t
140152
)
141153

142154
func NewLatLng(lat, lng float64) LatLng {
@@ -222,6 +234,7 @@ func GridDiskDistances(origin Cell, k int) ([][]Cell, error) {
222234
rsz := maxGridDiskSize(k)
223235
outHexes := make([]C.H3Index, rsz)
224236
outDists := make([]C.int, rsz)
237+
225238
if err := toErr(C.gridDiskDistances(C.H3Index(origin), C.int(k), &outHexes[0], &outDists[0])); err != nil {
226239
return nil, err
227240
}
@@ -276,6 +289,36 @@ func PolygonToCells(polygon GeoPolygon, resolution int) ([]Cell, error) {
276289
return cellsFromC(out, true, false), toErr(errC)
277290
}
278291

292+
// PolygonToCells takes a given GeoJSON-like data structure fills it with the
293+
// hexagon cells that are contained by the GeoJSON-like data structure.
294+
//
295+
// This implementation traces the GeoJSON geoloop(s) in cartesian space with
296+
// hexagons, tests them and their neighbors to be contained by the geoloop(s),
297+
// and then any newly found hexagons are used to test again until no new
298+
// hexagons are found.
299+
func PolygonToCellsExperimental(polygon GeoPolygon, resolution int, mode ContainmentMode, maxNumCellsReturn ...int64) ([]Cell, error) {
300+
var maxNumCells int64 = math.MaxInt64
301+
if len(maxNumCellsReturn) > 0 {
302+
maxNumCells = maxNumCellsReturn[0]
303+
}
304+
if len(polygon.GeoLoop) == 0 {
305+
return nil, nil
306+
}
307+
cpoly := allocCGeoPolygon(polygon)
308+
309+
defer freeCGeoPolygon(&cpoly)
310+
311+
maxLen := new(C.int64_t)
312+
if err := toErr(C.maxPolygonToCellsSizeExperimental(&cpoly, C.int(resolution), C.uint32_t(mode), maxLen)); err != nil {
313+
return nil, err
314+
}
315+
316+
out := make([]C.H3Index, *maxLen)
317+
errC := C.polygonToCellsExperimental(&cpoly, C.int(resolution), C.uint32_t(mode), C.int64_t(maxNumCells), &out[0])
318+
319+
return cellsFromC(out, true, false), toErr(errC)
320+
}
321+
279322
// PolygonToCells takes a given GeoJSON-like data structure fills it with the
280323
// hexagon cells that are contained by the GeoJSON-like data structure.
281324
//

h3_test.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,90 @@ func TestCellsToMultiPolygon(t *testing.T) {
637637
assertNil(t, res)
638638
}
639639

640+
func TestPolygonToCellsExperimental(t *testing.T) {
641+
t.Parallel()
642+
643+
t.Run("empty", func(t *testing.T) {
644+
t.Parallel()
645+
646+
for _, flag := range []ContainmentMode{
647+
ContainmentCenter,
648+
ContainmentFull,
649+
ContainmentOverlapping,
650+
ContainmentOverlappingBbox,
651+
} {
652+
cells, err := PolygonToCellsExperimental(GeoPolygon{}, 6, flag)
653+
if err != nil {
654+
t.Error(t)
655+
}
656+
657+
assertEqual(t, 0, len(cells))
658+
}
659+
})
660+
661+
t.Run("without holes", func(t *testing.T) {
662+
t.Parallel()
663+
664+
for _, flag := range []ContainmentMode{
665+
ContainmentCenter,
666+
ContainmentFull,
667+
ContainmentOverlapping,
668+
ContainmentOverlappingBbox,
669+
} {
670+
cells, err := PolygonToCellsExperimental(validGeoPolygonNoHoles, 6, flag)
671+
if err != nil {
672+
t.Error(t)
673+
}
674+
expectedCellCounts := map[ContainmentMode]int{
675+
ContainmentCenter: 7,
676+
ContainmentFull: 1,
677+
ContainmentOverlapping: 14,
678+
ContainmentOverlappingBbox: 21,
679+
}
680+
assertEqual(t, expectedCellCounts[flag], len(cells))
681+
}
682+
})
683+
684+
t.Run("with holes", func(t *testing.T) {
685+
t.Parallel()
686+
687+
for _, flag := range []ContainmentMode{
688+
ContainmentCenter,
689+
ContainmentFull,
690+
ContainmentOverlapping,
691+
ContainmentOverlappingBbox,
692+
} {
693+
cells, err := PolygonToCellsExperimental(validGeoPolygonHoles, 6, flag)
694+
if err != nil {
695+
t.Error(t)
696+
}
697+
expectedCellCounts := map[ContainmentMode]int{
698+
ContainmentCenter: 6,
699+
ContainmentFull: 0,
700+
ContainmentOverlapping: 14,
701+
ContainmentOverlappingBbox: 21,
702+
}
703+
704+
assertEqual(t, expectedCellCounts[flag], len(cells))
705+
}
706+
})
707+
708+
t.Run("busting memory", func(t *testing.T) {
709+
t.Parallel()
710+
711+
for _, flag := range []ContainmentMode{
712+
ContainmentCenter,
713+
ContainmentOverlapping,
714+
ContainmentOverlappingBbox,
715+
} {
716+
_, err := PolygonToCellsExperimental(validGeoPolygonHoles, 6, flag, 3)
717+
if err != ErrMemoryBounds {
718+
t.Error(t)
719+
}
720+
}
721+
})
722+
}
723+
640724
func TestGridPath(t *testing.T) {
641725
t.Parallel()
642726
path, err := lineStartCell.GridPath(lineEndCell)

0 commit comments

Comments
 (0)