Git Product home page Git Product logo

h3-go's Introduction

H3 Logo

Build Coverage Status Go Report Card License GoDoc H3 Version

H3-Go is looking for a maintainer familiar with Go, C, and H3. Volunteers welcome! Please get in touch with us on the H3 Slack.

H3-Go

This library provides Golang bindings for the H3 Core Library. For API reference, see the H3 Documentation.

This is v4 of this library, supporting H3 v4.

Check out v3 or checkout the git tag for the version you need.

Migrating from v3?

Check out v3 to v4 migration guide. There have been no breaking changes to the format of H3 indexes. Indexes generated by older versions can be parsed in v4, and vice-versa.

Usage

Prerequisites

H3-Go requires CGO (CGO_ENABLED=1) in order to be built. Go should do the right thing when including this library:

The cgo tool is enabled by default for native builds on systems where it is expected to work. It is disabled by default when cross-compiling. You can control this by setting the CGO_ENABLED environment variable when running the go tool: set it to 1 to enable the use of cgo, and to 0 to disable it. The go tool will set the build constraint "cgo" if cgo is enabled. The special import "C" implies the "cgo" build constraint, as though the file also said "// +build cgo". Therefore, if cgo is disabled, files that import "C" will not be built by the go tool. (For more about build constraints see https://golang.org/pkg/go/build/#hdr-Build_Constraints).

If you see errors/warnings like "build constraints exclude all Go files...", then the cgo build constraint is likely disabled; try setting CGO_ENABLED=1 environment variable in your go build step.

Installation

go get github.com/uber/h3-go/v4

Quickstart

import "github.com/uber/h3-go/v4"

func ExampleLatLngToCell() {
 latLng := h3.NewLatLng(37.775938728915946, -122.41795063018799)
 resolution := 9 // between 0 (biggest cell) and 15 (smallest cell)

 cell := h3.LatLngToCell(latLng, resolution)

 fmt.Printf("%s", cell)
 // Output:
 // 8928308280fffff
}

C API

Notes

  • LatLng returns Lat and Lng as degrees, instead of radians.
  • H3 C API function prefixes of get have been dropped in support of Golang's Getter naming style.
  • Convenience methods have been added to various types where that type was the main or only argument.

Bindings

C API Go API
latLngToCell LatLngToCell, LatLng#Cell
cellToLatLng CellToLatLng, Cell#LatLng
cellToBoundary CellToBoundary, Cell#Boundary
gridDisk GridDisk, Cell#GridDisk
gridDiskDistances GridDiskDistances, Cell#GridDiskDistances
gridRingUnsafe N/A
polygonToCells PolygonToCells, GeoPolygon#Cells
cellsToMultiPolygon TODO
degsToRads DegsToRads
radsToDegs RadsToDegs
greatCircleDistance GreatCircleDistance* (3/3)
getHexagonAreaAvg HexagonAreaAvg* (3/3)
cellArea CellArea* (3/3)
getHexagonEdgeLengthAvg HexagonEdgeLengthAvg* (2/2)
exactEdgeLength EdgeLength* (3/3)
getNumCells NumCells
getRes0Cells Res0Cells
getPentagons Pentagons
getResolution Resolution
getBaseCellNumber BaseCellNumber, Cell#BaseCellNumber
stringToH3 IndexFromString, Cell#UnmarshalText
h3ToString IndexToString, Cell#String, Cell#MarshalText
isValidCell Cell#IsValid
cellToParent Cell#Parent, Cell#ImmediateParent
cellToChildren Cell#Children Cell#ImmediateChildren
cellToCenterChild Cell#CenterChild
compactCells CompactCells
uncompactCells UncompactCells
isResClassIII Cell#IsResClassIII
isPentagon Cell#IsPentagon
getIcosahedronFaces Cell#IcosahedronFaces
areNeighborCells Cell#IsNeighbor
cellsToDirectedEdge Cell#DirectedEdge
isValidDirectedEdge DirectedEdge#IsValid
getDirectedEdgeOrigin DirectedEdge#Origin
getDirectedEdgeDestination DirectedEdge#Destination
directedEdgeToCells DirectedEdge#Cells
originToDirectedEdges Cell#DirectedEdges
directedEdgeToBoundary DirectedEdge#Boundary
cellToVertex TODO
cellToVertexes TODO
vertexToLatLng TODO
isValidVertex TODO
gridDistance GridDistance, Cell#GridDistance
gridPathCells GridPath, Cell#GridPath
cellToLocalIj CellToLocalIJ
localIjToCell LocalIJToCell

CGO

The H3 C source code and header files are copied into this project to optimize for portability. h3-go can be imported into any Go project for any platform that CGO supports.

Contributing

Pull requests and Github issues are welcome. Please read our contributing guide for more information.

Legal and Licensing

H3-Go is licensed under the Apache 2.0 License.

h3-go's People

Contributors

akhenakh avatar glacialspring avatar isaacbrodsky avatar jogly avatar keisar avatar moviejo avatar retbrown avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

h3-go's Issues

SetToLinkedGeo implementation not connected internally

Current implementation creates duplicated inner structure

/* Current */
func linkedGeoPolygonFromC(cg *C.LinkedGeoPolygon) LinkedGeoPolygon {
	g := LinkedGeoPolygon{}
	g.First = linkedGeoLoopFromC(cg.first)
	g.Last = linkedGeoLoopFromC(cg.last)

	if cg.next != nil {
		next := linkedGeoPolygonFromC(cg.next)
		g.Next = &next
	}

	return g
}

func linkedGeoLoopFromC(cg *C.LinkedGeoLoop) *LinkedGeoLoop {
	g := LinkedGeoLoop{}
	g.First = linkedGeoCoordFromC(cg.first)
	g.Last = linkedGeoCoordFromC(cg.last)

	if cg.next != nil {
		next := linkedGeoLoopFromC(cg.next)
		g.Next = next
	}

	return &g
}

func linkedGeoCoordFromC(cg *C.LinkedGeoCoord) *LinkedGeoCoord {
	g := LinkedGeoCoord{}
	g.Vertex = geoCoordFromC(cg.vertex)

	if cg.next != nil {
		next := linkedGeoCoordFromC(cg.next)
		g.Next = next
	}

	return &g
}

Suppose that one GeoPolygon has 3 GeoLoops, the following data structure will be created.

GeoPolygon A
- First: GeoLoop B
- Last: GeoLoop E
- Next: nil

GeoLoop B
- Next: GeoLoop C

GeoLoop C
- Next: GeoLoop D

GeoLoop D
- Next: nil

GeoLoop E
- Next: nil

GeoLoop D and GeoLoop E have the same data (GeoCoord) internally, but are created as separate objects

This problem also occurs with the same implementations of GeoLoop and GeoCoord.

Therefore, if implemented to connect the last object of LinkedList to Last as shown below,
Structure as LinkedList also works normally, and unnecessary memory consumption can be reduced.

func linkedGeoPolygonFromC(cg *C.LinkedGeoPolygon) LinkedGeoPolygon {
	g := LinkedGeoPolygon{}
	glf, gll := linkedGeoLoopFromC(cg.first)
	g.First = glf
	g.Last = gll
	/* Don't need last pointer of GeoPolygon */

	if cg.next != nil {
		next := linkedGeoPolygonFromC(cg.next)
		g.Next = &next
	}

	return g
}

func linkedGeoLoopFromC(cg *C.LinkedGeoLoop) (*LinkedGeoLoop, *LinkedGeoLoop) {
	g := LinkedGeoLoop{}
	gcf, gcl := linkedGeoCoordFromC(cg.first)
	g.First = gcf
	g.Last = gcl
	l := &g

	if cg.next != nil {
		next, last := linkedGeoLoopFromC(cg.next)
		g.Next = next
		l = last
	}

	return &g, l
}

func linkedGeoCoordFromC(cg *C.LinkedGeoCoord) (*LinkedGeoCoord, *LinkedGeoCoord) {
	g := LinkedGeoCoord{}
	g.Vertex = geoCoordFromC(cg.vertex)
	l := &g

	if cg.next != nil {
		next, last := linkedGeoCoordFromC(cg.next)
		g.Next = next
		l = last
	}

	return &g, l
}

Support Go Modules

https://blog.golang.org/v2-go-modules

I will add a v3 module with a patch version bump to comply with the go modules pattern. This will not break existing users, with or without go modules, because go module users will have to opt-in to using the new github.com/uber/h3-go/v3 import path.

plan for future development

all changes and improvements to v3.* will be made in the v3/ module, leaving the root module as-is. Users of the root module will need to move to the GOMODULE supported /v3 suffix import (github.com/uber/h3-go/v3) to pick up any changes/fixes introduced after v3.0.2.

rationale

future development will be made in the v3 module and not reflected in the root module in order to avoid copy/paste mistakes. Developing in the v3 module will also encourage adoption of the backwards compatible development practices encouraged by GOMODULES.

Library doesn't build when using mod=vendor

When using vendor mode .h files are not copied to the vendor directory because they are in a subdirectory, according to cgo's documentation (https://golang.org/cmd/cgo/) we should not put non-go files in subdirectories.

I have created a fork with all .h files moved from the /include/ subdirectory to the parent library (keisar#1), after these changes the library works in vendor mode.
If all agree I will create the PR here as well.

Another possible solution is to follow this approach: https://github.com/godror/godror/pull/38/files
which means creating dummy go files in the /include subdirectories and importing them from h3.go.
If you prefer I can send a PR for this approach as well.

Related issue: #16

Build Issue with go mod

How to build uber h3 go lib with go mod?

Command

RUN CGO_ENABLED=1 go build -o appName

Error
github.com/uber/h3-go
exec: "gcc": executable file not found in $PATH

Thanks for the help.

Running clang failed

I'm using ToGeoBoundary and Polyfill functions in an AWS lambda. When I attempt to compile locally, with CGO_ENABLED=1, this is my output.

/usr/local/Cellar/go/1.13.6/libexec/pkg/tool/darwin_amd64/link: running clang failed: exit status 1
ld: warning: ignoring file /var/folders/_z/3p5qswxd5hjbn4yc_075s1d00000gp/T/go-link-559327432/go.o, building for macOS-x86_64 but attempting to link with file built for unknown-unsupported file format ( 0x7F 0x45 0x4C 0x46 0x02 0x01 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 )
Undefined symbols for architecture x86_64:
  "__cgo_topofstack", referenced from:
      __cgo_ebeccfde5ab6_Cfunc_compact in 000001.o
      __cgo_ebeccfde5ab6_Cfunc_geoToH3 in 000001.o
      __cgo_ebeccfde5ab6_Cfunc_getDestinationH3IndexFromUnidirectionalEdge in 000001.o
      __cgo_ebeccfde5ab6_Cfunc_getH3UnidirectionalEdge in 000001.o
      __cgo_ebeccfde5ab6_Cfunc_getOriginH3IndexFromUnidirectionalEdge in 000001.o
      __cgo_ebeccfde5ab6_Cfunc_h3GetBaseCell in 000001.o
      __cgo_ebeccfde5ab6_Cfunc_h3GetResolution in 000001.o
      ...
  "_main", referenced from:
     implicit entry/start for main executable
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Any help would be appreciated.

ToGeo function return values inconsistent

The H3 Go function h3.ToGeo(h3.Index) returns a value which is out by 360 degrees compared to the Python implementation. An example illustrates the point below.

Python functions return the following:

h3_address = h3.geo_to_h3(51.5233512, -0.0810132, 12)

center_point = h3.h3_to_geo(h3_address)

print(h3_address)
print(center_point)
'8c194ad30d067ff'
[51.523416454245556, -0.08106823052469281]

Go Lang functions return the following:

func main() {

	geo := h3.GeoCoord{
		Latitude:  51.5233512,
		Longitude: -0.0810132,
	}

	h3Address := h3.FromGeo(geo, 12)
	centerPoint := h3.ToGeo(h3_address)

	fmt.Println(h3Address)
	fmt.Println(centerPoint)
}
630948894377797631
{51.52341645424555 359.9189317694753}
Lang Longitude Val
Python -0.08106823052469281
Go 359.9189317694753

This seems inconsistent - While I understand the type of the address changes between Python(String) and GoLang(uint64) for good reasons. The value of the ToGeo functions varies by 360 exactly. This isn't a difficult fix within a system but I don't understand the inconsistency.

Invalid h3 index on arm

I've fixed the problem i had with longitude like in the issue #7, but when i'm trying to use the same source code using h3 on a raspberry pi, the indexes generated by the h3 library are not the same as the one generated by the cli tools.

From H3-go

371730345

which gives me those boundaries

{
   68.929957882 31.831280499
   69.393596490 62.345344957
   76.163042830 94.143090102
   87.364695323 145.558197691
   81.271371790 -34.758417980
   73.310223685 0.325610352
}

From CLI

8a2bac516287fff

which gives me the right boundaries

{
   46.811976430 -71.244156240
   46.811843377 -71.245203899
   46.811174262 -71.245565993
   46.810638208 -71.244880450
   46.810771256 -71.243832820
   46.811440363 -71.243470704
}

error=failed to build for windows_386: exit status 1: package [appname]: build constraints exclude all Go files in [path to app]

When I use the basic template for the .goreleaser.yaml, I get the following error:

error=failed to build for windows_386: exit status 1: package [appname]: build constraints exclude all Go files in [path to app files]
error=failed to build for amd64_v1: exit status 1: package [appname]: build constraints exclude all Go files in [path to app files]

It doesn't matter what I remove - there is always the same error on a different release.

I have read the docs and other sources to no avail. Even on discord which was not active.

v3.0.2+ not working correctly with go modules

versions after v3.0.1 don't seem to show up in goproxy:

$ curl https://proxy.golang.org/github.com/uber/h3-go/@v/list
v3.0.0+incompatible
v3.0.1+incompatible

and when querying for them directly throw go mod related errors:

$ curl https://proxy.golang.org/github.com/uber/h3-go/@v/v3.0.1.info
{"Version":"v3.0.1+incompatible","Time":"2019-06-03T19:03:32Z"}
$ curl https://proxy.golang.org/github.com/uber/h3-go/@v/v3.0.2.info
not found: github.com/uber/[email protected]: invalid version: module contains a go.mod file, so major version must be compatible: should be v0 or v1, not v3

As a result, when trying out the example from the readme:

$ cat main.go
package main

import (
    "fmt"
    "github.com/uber/h3-go"
)

func main() {
        geo := h3.GeoCoord{
                Latitude:  37.775938728915946,
                Longitude: -122.41795063018799,
        }
        resolution := 9
        fmt.Printf("%#x\n", h3.FromGeo(geo, resolution))
        // Output:
        // 0x8928308280fffff
}
$ go run main.go 
go: finding module for package github.com/uber/h3-go
go: found github.com/uber/h3-go in github.com/uber/h3-go v3.0.1+incompatible

ends up downloading an old version. When manually editing go.mod to a more recent version, you get:

$ go run main.go # with edited go.mod to v3.0.2
go.mod:5: require github.com/uber/h3-go: version "v3.0.2" invalid: module contains a go.mod file, so major version must be compatible: should be v0 or v1, not v3
$ go run main.go # with edited go.mod to v3.0.2+incompatible
go: github.com/uber/[email protected]+incompatible/go.mod: verifying module: github.com/uber/[email protected]+incompatible/go.mod: reading https://sum.golang.org/lookup/github.com/uber/[email protected]+incompatible: 410 Gone
        server response: not found: github.com/uber/[email protected]+incompatible: invalid version: +incompatible suffix not allowed: module contains a go.mod file, so semantic import versioning is required

Polyfill

How to convert a boundary (polygon) to hexagons with a resolution using uber h3 golang bindings?

Similar to this in java~


 @Test
    public void testPolyfillLarge() {
        List<Long> hexagons = h3.polyfill(
                ImmutableList.<GeoCoord>of(
                        new GeoCoord(41.5, -70.4),
                        new GeoCoord(41.5, -69.8),
                        new GeoCoord(42.1, -69.8),
                        new GeoCoord(42.1, -70.4)
                ), null,
                10
        );

        assertTrue(hexagons.size() > 1000);
    }

Thanks

Indexes don't match (h3-js and h3-go)

Hi, I'm very new to this library and I'm using it in a project i'm working on.
My backend is in go and my frontend is in react.

Problem.

When I pin-point 2 locations on a map in the same hexagon, I expect them to be have the same index. Which works as expected on the frontend.
But when I index them on the backend, I get 2 different indices.

Sample Data I'm working with;

Location 1
{
    "driver_id": "1",
    "lat": "5.679056546966131",
    "lng": "-0.2408966745733654"
}

Location 2
{
    "lat": "5.6822593911240595",
    "lng": "-0.2415833200811779"
}

Resolution = 8

Aside

So just to test verify my logic, i found the center on of all the indices I had on the backend.
and when I plotted them on the frontend, I noticed they were all in different hexagons even though the initial points were from 1 hexagon.

Picking Coordinate Stage
Screen Shot 2020-05-15 at 4 42 09 PM

After indexing coordinates and finding the center of the indices
Screen Shot 2020-05-15 at 4 42 30 PM

Could this be the problem? and If yes, how do I resolve that.
Screen Shot 2020-05-15 at 4 23 49 PM

Thanks in advance and great project btw. Helped me a lot

incomplete result when using SetToLinkedGeo

The linkedGeoPolygonFromC is not setting the Next field. It should be doing something like this:

func linkedGeoPolygonFromC(cg *C.LinkedGeoPolygon) LinkedGeoPolygon {
	g := LinkedGeoPolygon{}
	g.First = linkedGeoLoopFromC(cg.first)
	g.Last = linkedGeoLoopFromC(cg.last)

	if cg.next != nil {
		next := linkedGeoPolygonFromC(cg.next)
		g.Next = &next
	}

	return g
}
The result is that sets of H3Index that would result in a multipolygon only contain a single polygon. This is a (not minimal) example of one such set:
var indexes = []h3.H3Index{
	0x89194ad36a3ffff,
	0x89194ad3263ffff,
	0x89194ad326fffff,
	0x89194ad149bffff,
	0x89194ad1493ffff,
	0x89194ad322bffff,
	0x89194ad3277ffff,
	0x89194ad338bffff,
	0x89194ad3313ffff,
	0x89194ad3317ffff,
	0x89194ad33bbffff,
	0x89194ad3387ffff,
	0x89194ad3383ffff,
	0x89194ad3397ffff,
	0x89194ad33b3ffff,
	0x89194ad314fffff,
	0x89194ad3143ffff,
	0x89194ad315bffff,
	0x88194ad369fffff,
	0x88194ad361fffff,
	0x88194ad363fffff,
	0x88194ad30dfffff,
	0x88194ad347fffff,
	0x88194ad345fffff,
}

Rendering all H3Index with ToGeoBoundary results in something like this:

image

Using SetToLinkedGeo instead discards all but one of the polygons, giving something like this:

image

With the change specified above, the output of SetToLinkedGeo looks correct:

image

Issue when importing h3 package

I imported uber h3 backage but getting this error on build

# voyager/vendor/github.com/uber/h3-go vendor/github.com/uber/h3-go/h3.go:27:10: fatal error: 'h3api.h' file not found #include <h3api.h> ^~~~~~~~~ 1 error generated.

Using dep for dependencies.

Thanks for the help.

Upgrade h3 core to 3.5+

Could someone upgrade the h3 core to something newer than 3.5 and add the h3GetFaces bindings please?

miscellaneous methods are missing

miscellaneous methods are not implemented in go v3

double H3_EXPORT(degsToRads)(double degrees);
double H3_EXPORT(radsToDegs)(double radians);
double H3_EXPORT(pointDistRads)(const GeoCoord *a, const GeoCoord *b);
double H3_EXPORT(pointDistKm)(const GeoCoord *a, const GeoCoord *b);
double H3_EXPORT(pointDistM)(const GeoCoord *a, const GeoCoord *b);
double H3_EXPORT(hexAreaKm2)(int res);
double H3_EXPORT(hexAreaM2)(int res);
double H3_EXPORT(cellAreaRads2)(H3Index h);
double H3_EXPORT(cellAreaKm2)(H3Index h);
double H3_EXPORT(cellAreaM2)(H3Index h);
double H3_EXPORT(edgeLengthKm)(int res);
double H3_EXPORT(edgeLengthM)(int res);
double H3_EXPORT(exactEdgeLengthRads)(H3Index edge);
double H3_EXPORT(exactEdgeLengthKm)(H3Index edge);
double H3_EXPORT(exactEdgeLengthM)(H3Index edge);
int64_t H3_EXPORT(numHexagons)(int res);
int H3_EXPORT(res0IndexCount)();
void H3_EXPORT(getRes0Indexes)(H3Index *out);
int H3_EXPORT(pentagonIndexCount)();
void H3_EXPORT(getPentagonIndexes)(int res, H3Index *out);

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.