Skip to content

Commit a62cc2b

Browse files
justinhwangclaude
andcommitted
refactor: remove internal/h3core and reorganize x/h3go
Remove the internal/h3core package and inline the shared H3 index-format constants and pentagon base-cell table into both consumers, so neither depends on the shared package: - h3: bit-layout constants become literals (or C macros where the block already uses them); the pentagon table becomes a package-level var. - x/h3go: same constants and pentagon table inlined, keeping the package fully cgo-free and self-contained. Reorganize x/h3go alongside the inlining: - Group const/var/type declaration blocks at the top of each source file. - Split error vars into errors.go; rename h3go.go -> constants.go and add h3.go for the package doc. - Move type declarations out of constants.go into the files where their methods live (projection primitives -> faceijk.go, etc.). - Convert bboxFromGeoLoop/bboxesFromGeoPolygon to methods (GeoLoop.toBbox / GeoPolygon.toBboxes). - Replace the shared Cell bit-manipulation methods with generic functions over the Index constraint (modeOf, reservedBits, resolution, indexDigit, indexDigitChecked, ownerCell) so DirectedEdge and Vertex no longer cast to Cell to reuse them; no DirectedEdge/Vertex -> Cell casts remain. - Add a typed `mode` (iota: cellMode=1, directedEdgeMode=2, edgeMode=3 unused, vertexMode=4); modeOf returns it. No behavior change; parity tests, 100% coverage, vet, and golangci-lint all pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 0fb254b commit a62cc2b

26 files changed

Lines changed: 1536 additions & 1541 deletions

h3.go

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,6 @@ import (
3939
"strconv"
4040
"strings"
4141
"unsafe"
42-
43-
"github.com/uber/h3-go/v4/internal/h3core"
4442
)
4543

4644
const (
@@ -49,7 +47,7 @@ const (
4947
MaxCellBndryVerts = C.MAX_CELL_BNDRY_VERTS
5048

5149
// MaxResolution is the maximum H3 resolution a LatLng can be indexed to.
52-
MaxResolution = h3core.MaxResolution
50+
MaxResolution = C.MAX_H3_RES
5351

5452
// NumIcosaFaces is the number of faces on an icosahedron.
5553
NumIcosaFaces = C.NUM_ICOSA_FACES
@@ -85,18 +83,18 @@ const (
8583
// to avoid re-allocation.
8684
latLngStringSize = 32
8785

88-
cellMode = h3core.CellMode
89-
directedEdgeMode = h3core.DirectedEdgeMode
90-
vertexMode = h3core.VertexMode
91-
modeOffset = h3core.ModeOffset
86+
cellMode = 1 // H3_CELL_MODE
87+
directedEdgeMode = 2 // H3_DIRECTEDEDGE_MODE
88+
vertexMode = 4 // H3_VERTEX_MODE
89+
modeOffset = 59 // H3_MODE_OFFSET
9290
reservedOffset = 56 // H3_RESERVED_OFFSET
93-
resolutionOffset = h3core.ResolutionOffset
94-
baseCellOffset = h3core.BaseCellOffset
95-
perDigitOffset = h3core.PerDigitOffset
96-
digitMask = h3core.DigitMask
91+
resolutionOffset = 52 // H3_RES_OFFSET
92+
baseCellOffset = 45 // H3_BC_OFFSET
93+
perDigitOffset = 3 // H3_PER_DIGIT_OFFSET
94+
digitMask = 7 // H3_DIGIT_MASK
9795
earthRadiusKm = C.EARTH_RADIUS_KM
9896

99-
resolutionMask = h3core.ResolutionMask
97+
resolutionMask = 0xF // low 4 bits of the resolution field
10098
baseCellMask = 0x7F // 7 bits
10199
modeMask = 0xF // 4 bits
102100

@@ -131,6 +129,14 @@ var (
131129
}
132130
// compile-time check: pow7 must have exactly MaxResolution+1 entries.
133131
_ = pow7[MaxResolution]
132+
133+
// isBaseCellPentagon maps base cell number to whether it is a pentagon.
134+
// There are exactly 12 pentagons at every resolution, one for each vertex
135+
// of the icosahedron.
136+
isBaseCellPentagon = [128]bool{
137+
4: true, 14: true, 24: true, 38: true, 49: true, 58: true,
138+
63: true, 72: true, 83: true, 97: true, 107: true, 117: true,
139+
}
134140
)
135141

136142
// PolygonToCells containment modes
@@ -1590,7 +1596,7 @@ func hasAll7AfterRes(h uint64, res int) bool {
15901596
}
15911597

15921598
func hasDeletedSubsequence(h uint64, baseCell int) bool {
1593-
if !h3core.IsBaseCellPentagon[baseCell] {
1599+
if !isBaseCellPentagon[baseCell] {
15941600
return false
15951601
}
15961602
h <<= digitRegionOffset
@@ -1606,7 +1612,7 @@ func firstOneIndex(h uint64) int {
16061612
}
16071613

16081614
func isPentagonCell(c Cell) bool {
1609-
if !h3core.IsBaseCellPentagon[baseCellNumber(c)] {
1615+
if !isBaseCellPentagon[baseCellNumber(c)] {
16101616
return false
16111617
}
16121618
for r := 1; r <= resolution(c); r++ {

internal/h3core/h3core.go

Lines changed: 0 additions & 61 deletions
This file was deleted.

x/h3go/bbox.go

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,26 +18,19 @@ package h3go
1818

1919
import "math"
2020

21-
// bbox is a geographic bounding box with degree coordinates, matching the units
22-
// of the public GeoPolygon. east < west indicates a box crossing the
23-
// antimeridian.
24-
type bbox struct {
25-
north, south, east, west float64
26-
}
27-
2821
// Longitude span constants in degrees, the units of the public API. They stand
2922
// in for the H3 C library's radian M_PI / M_2PI when detecting and normalizing
3023
// antimeridian-crossing geometry.
3124
const (
3225
piDeg = 180.0
3326
twoPiDeg = 360.0
3427
halfPiDeg = 90.0
35-
)
3628

37-
// twoPiRad is a full longitude turn in radians, used to normalize
38-
// antimeridian-crossing geometry where the math must run at the radian scale of
39-
// the H3 C library.
40-
const twoPiRad = 2 * math.Pi
29+
// twoPiRad is a full longitude turn in radians, used to normalize
30+
// antimeridian-crossing geometry where the math must run at the radian scale
31+
// of the H3 C library.
32+
twoPiRad = 2 * math.Pi
33+
)
4134

4235
// longitudeNormalization selects how a longitude is shifted so two bounding
4336
// boxes, either of which may cross the antimeridian, can be compared in one
@@ -50,6 +43,13 @@ const (
5043
normalizeWest
5144
)
5245

46+
// bbox is a geographic bounding box with degree coordinates, matching the units
47+
// of the public GeoPolygon. east < west indicates a box crossing the
48+
// antimeridian.
49+
type bbox struct {
50+
north, south, east, west float64
51+
}
52+
5353
// isTransmeridian reports whether the bounding box crosses the antimeridian.
5454
func (b bbox) isTransmeridian() bool {
5555
return b.east < b.west
@@ -68,10 +68,10 @@ func (b bbox) contains(point LatLng) bool {
6868
return point.Lng >= b.west && point.Lng <= b.east
6969
}
7070

71-
// bboxFromGeoLoop computes the bounding box of a loop of coordinates. It does not
71+
// toBbox computes the bounding box of a loop of coordinates. It does not
7272
// support loops with adjacent points more than 180° of longitude apart (treated
7373
// as antimeridian crossings) or loops containing a pole.
74-
func bboxFromGeoLoop(loop GeoLoop) bbox {
74+
func (loop GeoLoop) toBbox() bbox {
7575
if len(loop) == 0 {
7676
return bbox{}
7777
}
@@ -111,14 +111,14 @@ func bboxFromGeoLoop(loop GeoLoop) bbox {
111111
return out
112112
}
113113

114-
// bboxesFromGeoPolygon returns the bounding box for the outer loop followed by
114+
// toBboxes returns the bounding box for the outer loop followed by
115115
// one for each hole, in order.
116-
func bboxesFromGeoPolygon(polygon GeoPolygon) []bbox {
116+
func (polygon GeoPolygon) toBboxes() []bbox {
117117
bboxes := make([]bbox, len(polygon.Holes)+1)
118-
bboxes[0] = bboxFromGeoLoop(polygon.GeoLoop)
118+
bboxes[0] = polygon.GeoLoop.toBbox()
119119

120120
for i := range polygon.Holes {
121-
bboxes[i+1] = bboxFromGeoLoop(polygon.Holes[i])
121+
bboxes[i+1] = polygon.Holes[i].toBbox()
122122
}
123123

124124
return bboxes

x/h3go/boundary.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,13 @@
1616

1717
package h3go
1818

19+
type (
20+
// CellBoundary is the ordered set of geographic vertices that outline a cell.
21+
// It never has more vertices than a cell has topological vertices plus its
22+
// distortion vertices.
23+
CellBoundary []LatLng
24+
)
25+
1926
// CellToBoundary returns the geographic boundary of a cell as an ordered list of
2027
// vertices in degrees.
2128
func CellToBoundary(c Cell) (CellBoundary, error) {

0 commit comments

Comments
 (0)