Requesting comments re recent research on Hierarchical Hexagonal Grids.

Over the last 15 months, I have been slowly working on a novel hierarchical hexagonal grid, based upon the key insight that while one cannot tile hexagons with hexagons, one can tile half-hexagons with half-hexagons.

It’s been a journey, and I’ve had a lot of help from various people in the field. The grid system uses an octahedral projection, and involves quite a few novel aspects.

It’s pretty accurate. It supports near-lossless forward and inverse transforms to arbitrary depth, and is especially well-suited to hex-based tiling systems. I have a working implementation in Python with sub-millimeter accuracy using geodesics, and I’m considering a native port to C++ for potential integration with PROJ.

A sample of results (round trip is via the Hex addressing themselves)

Stonehenge    	
Reference GCD: [51.17886302 -1.82617712]
Roundtrip GCD: [51.17886302 -1.82617712] 
Address  :NWΛ01357247546275133355V0 

Los Organos, La Gomera   
Reference GCD: [28.21893217 -17.28230155]
Roundtrip GCD: [28.21893217 -17.28230155]
Address  :WAΛ82524022847627233383V0

Healing Pond, Cat Island 
Reference GCD: [24.18541798 -75.32541004]
Roundtrip GCD: [24.18541798 -75.32541004]
Address  :NAΛ12651744507738008106V1

Statue of Liberty
Reference GCD: [40.68936032 -74.0445505]
Roundtrip GCD: [40.68936033 -74.0445505]
Address  :NAΛ55836342885310738272V0

Great Pyramid
Reference GCD: [29.97916252 31.13426302]
Roundtrip GCD: [29.97916252 31.13426302]
Address  :EAV48452028481533576536Λ2

The following image represents the fundamental structure of the entire grid.

The grid system itself is not tied to a specific projection, but I’ve also worked on that, (along with standard conformal projections) and, while I don’t really know about the GIS world, it seems to be pretty robust.
Here is layer five on conformal.

One of the key features is that the entire grid is geometric - there are no databases of grid points (beyond the six vertices of the octahedron) - and the shape of any cell at any level can be derived from the underlying projection itself.

I developed this for the purposes of hex-binning - but it may have other uses too.
The projection and grid together offer a bidirectional, distortion-aware, hierarchical projection of the Earth onto an octahedron, with uniform resolution scaling that tops out only at the numerical error of the system it’s running on. The grid part of the project uses well-defined mathematics - depending almost solely on resolving inequalities. The tiling above may look complex at first, but it depends upon insights relating strongly to the underlying symmetries (and brought to life by Shephard/Grunbaum, amongst others), which are further amended to support the cyclical nature of the sphere.
There is no dateline discontinuity, or poles. (Well, on conformal there are six poles - but that’s an artefact of conformal) There are also no degenerate tiles, or ragged edges, or ambiguities.

It’s a unversal spatial index (for surfaces!) with an arbitrary depth, precise translation to Euclidean geometry, and maintains all the advantages of hexagonal grids, while offering a robust hierarchy model that is (in my opinion) far stronger, more intuitive, and more available than many other existing systems.

Here is one net of the non-conformal projection - it’s not too shabby.

and again with tissot’ indicatrix

Here are the 12 root 0 hexagons along with the layer-1 hexagons (following a different net).

I have now finished with all the challenges I faced - apart from finalising my documentation, rewriting some of the examples, and pushing all of the fixes and finding onto the public repo.

What I want to know is - is there any interest at all for any of this sort of work? Have I been doing something that nobody else is remotely interested in?

4 Likes

Hey @BenGriffin welcome to the discussion forum, while I responded with a :open_mouth: yesterday I wanted to respond with some actual encouragement today since nobody has replied yet.

That is a really impressive bit of work! For folks who love this kind of stuff you may need to share with the PROJ or GeoTools project where the reprojection engines live.

1 Like

Hi!
Thanks for the warm words and encouragement.
Up to now I’ve been in a somewhat frenzied bubble trying to ensure that everything works as it should!
I will seek out those forae also, and repost.

Do you have your python work published somewhere where people can test? I’m thinking depending on complexity, might be something that can be incorporated in PostGIS For example like our hexagon grid - https://postgis.net/docs/ST_HexagonGrid.html

1 Like

Hey - that sounds really interesting!
I do need to clear up some of the latest fixes, but it sounds encouraging! I’ll update you soon!

Okay I have fixed the existing examples against the current codebase.

The documentation needs updating still - it does well on the fundamental planar, but does not cover the details of the octahedral enumeration properly.

1 Like

I know it’s been a while but I have managed to incorporate into PostGIS (the sql is contained within the repo). I’ve also written a PROJ CRS for it, but I’m dubious if it’s going to be acceptable. My next need is to write a paper, which is a bit daunting for me! The hhg9/hex9 project has improved since June. See my recent reddit post, for example (if you can bear reddit). the_map_is_the_grid A recent insight is that Hex9 particularly interesting is that, because the scheme is fractal, the hexagons go on indefinitely, one ends up with a DGG that can go infinitely small - which means that each infinitesimal hexagon is also a point: IE, Both a DGG and a CRS at the same time.

Hi Ben,

Where is the sql in the repo? I’m seeing a bunch of python files but no sql file here - GitHub - MrBenGriffin/hex9: work on hierarchical hexagonal grids · GitHub

Ideally we’d want a fork of the postgis repo to even consider accepting and then a pull request. Worst we’ll do is reject, but that’s the best way to get the ball rolling.

You can do a pull request on our primary or any of our mirrors. Source Code | PostGIS

Good shout. I will get on a PR.

The sql was not yet on the repo! My bad. It’s now at /sql/h9_postgis.sql
However, it is definitely in ‘development mode’.

I have a few questions, if you wouldn’t mind.

In Hex9, the CRS and the DGGS are the same thing. The ‘octahedral barycentric’ transform is not a projection that a grid is then overlaid onto — the hierarchical cell addressing falls out of the transform itself. A UUID* at any layer is simply a quantised position in the CRS. This is what distinguishes Hex9 from other DGGS, and it is why ST_Transform is a meaningful long-term goal rather than a category error. It also answers the ISO objection: Hex9 is a projection that has a natural discrete hierarchy as a consequence, it is not a DGGS that happens to use a projection.

*As implied, the approach uses PostgreSQL’s native UUID type for cell IDs, which integrates naturally with indexing and generated columns.

Further questions re. the PR.

(1) Separate extension or core?
The Hex9 math is more self-contained than those but introduces novel concepts (UUID cell IDs, octahedral hierarchy) that may feel out of place in core.

(2) If not a separate extension, would the maintainers be comfortable accepting a PR that embeds novel geodetic math (beam search, authalic warp) directly in PostGIS C code, without PROJ backing?

(The maths is already validated, with sub-15nm round-trip).
H3-pg sets a precedent for embedding a DGGS C library in a PostGIS extension. The question is whether PostGIS core (vs. a contrib extension) is the right home, or whether this should be a separate postgis_hex9 extension.

(3) Would ST_Hex9Neighbours (adjacent cell lookup) be necessarily in-scope for the initial
PR?

While this is useful for spatial analysis, it might require understanding the Hex9 topology. Hierarchical roll-up/roll-down via UUID truncation covers most real analysis patterns, and neighbours can be added in a follow-on PR without breaking the initial API.

(4) Would there be an expectation that ST_Transform to/from the Hex9 CRS would work, and if not, should the CRS even be registered in spatial_ref_sys at all?

I could generate just the results via API, rather than expose the underlying CRS. This might be a better entry point? It would make the PR reviewable on its merits as a useful spatial function, rather than as a geodetic framework, which might be a better entry point.

Kind regards
Ben.

On 29 Mar 2026, at 09:40, Regina Obe noreply@discourse.osgeo.org wrote:

robe
March 29

Hi Ben,

Where is the sql in the repo? I’m seeing a bunch of python files but no sql file here

Ideally we’d want a fork of the postgis repo to even consider accepting and then a pull request. Worst we’ll do is reject, but that’s the best way to get the ball rolling.

You can do a pull request on our primary or any of our mirrors.

Your sql as it stands can’t be part of Postgis because of the reliance on plpython so it would need to be a separate extension. Main reason for rejecting plpython is most environments users will be running Postgis will not allow plpython because it’s an untrusted language. Even f it were trusted it would add yet another dependency in our scope of many dependencies already.

1 Like

Hi Regina,

Yeah, that SQL was really a proof-of-concept.

I am on holiday at the moment, and have a few more structural pieces that I want to implement before writing the extension - which will be in C++. There is a small warp look-up table, (generated via SinkHorn analysis) which I would probably include as a header.

I will use an existing extension as a starting point.

If demand for the CRS arises, we can deal with that later on.

1 Like

Hi there Ben, congratulations for this work. Some remarks below.

This kind of systems are more powerful when applying an equal-area projection. Otherwise the zone sizes become too heterogenous (as can be seen in the globe image). John Snyder published an equal-area projection for the platonic solids in 1992, which has been the most used since. In the past couple of years Jérôme St-Louis has greatly improved Snyder’s method and updated its implementation in PROJ. The most recent chapter has had the [contribution of Felix Palmer](Feature: Snyder Polyhedral Equal Area projections by felixpalmer · Pull Request #4758 · OSGeo/PROJ · GitHub).

You use aperture 9, which to speak the truth I hadn’t see before. Whereas it looks fairly straightforwards, it refines the grid quite “fast”, getting to millions of zones with just a few refinements. Both IGeo7 and H3 are criticised for that aspect, and those are aperture 7. However, there are always use cases in which an alternative aperture or index can be beneficial.

In any case, I would invite you to contribute the hexagonal aperture 9 index to the [GeoPlegma](GitHub - GeoPlegma/GeoPlegma: Harbouring development of geo-spatial tools for Discrete Global Grid Systems · GitHub) project. Get in touch if you wish to know more about the project or for an introduction.

Best.

1 Like

Brilliant - I will get in touch in due course.

Equal Area without distortion is always an impossibility - but I feel my current model is doing well there.
I’ve been working on a paper (not a strength) and a C++ standalone extension for PostGIS (after encouragement!) - hoping to get onto OGC. The maths / coding work is very strong already.

Let me know once you have the C++ extension ready. Happy to compile and test and if I can compile without issue I can include it in the windows spatial extension bundle I manage along side the other spatial extensions - Latest Released Version | PostGIS

1 Like

Hi Regina - thank-you so much for your thoughts - yes - I am busy but I am also really keen to get something to you soon. The core projections are converted, and I’m working on the address encoding, decoding, and then finishing off the API.

@Lads, let me give you a current reading of Hex9 re. equal area…

An equal area summary for the 708,588 hexagons of layer 5 under WGS84. (Ideal area is calculated by dividing the WGS84 surface area by the number of hexagons)
Area min/max/ ideal: 717,461,468 / 720,534,040 / 719,833,841m²

99% of cells are within 0.014% of the target area. The worst deviations are at the six octahedral vertex singularities which, while topologically equivalent are geometrically asymmetric on WGS84: The polar vertices carry an additional area compression from the ellipsoidal oblateness, producing more pronounced warp residuals there than at the 4 equatorial vertices. All cell locations are known and fixed at every resolution level.

Area: % dev min/mean/max: -0.32957226% / +0.00000000% / +0.09727235% log-ratio std dev : 0.00005240
|% dev| p50/p90/p95/p99/p99.9/p99.99: 0.00277048% / 0.00524091% / 0.00803308% / 0.01403624% / 0.04771097% / 0.13311261%

Cells are convex hexagons everywhere. The median cell has a longest-to-shortest edge ratio of ~1.33. The 99th-percentile ratio is ~1.49. This is the shape cost of minimising area deviation — a strictly equal-area constraint (e.g. Snyder octahedral) permits unbounded elongation in exchange for exact det(J)=1. Hex9’s Sinkhorn/OT derivation implicitly regularises against shear, bounding shape distortion at the cost of a small area residual.

Edge span (max:min ratio): p50/p90/p95/p99/p99.9/p99.99: 1.33 / 1.39 / 1.40 / 1.49 / 1.61 / 1.63
Edge regularity (edge-length CV): p50/p90/p95/p99/p99.9/p99.99: 12.0% / 13.7% / 13.9% / 15.9% / 18.7% / 19.4%

I understand that H3 offers hexagonal cells but is not equal-area and operates on a sphere. S2 and HEALPix are neither hexagonal nor ellipsoidal — HEALPix achieves strict equal-area within that constraint. Hex9 is a system that is simultaneously hexagonal, near to equal-area, and defined on the WGS84 ellipsoid.

1 Like

We try to stick with just C code in our extension code and any c++ is relegated to a dependency library. Your tests also follow the PostgreSQL standard pattern, not the PostGIS style tests.

But let me see if I can at least compile it and regress. I think it might be too late for PostGIS 3.7 at anyrate because PostgreSQL 19beta is coming out very soon and we need to start wrapping up our cycle with what we have so we can make it in time for PostgreSQL 19 release.

Hi Regina - I pulled the last PR because I realised that there may be bits missing. I can probably refactor to C, and can definitely rewrite the test system. Definitely closing in.

I would have loved this code to be included in this cycle - but I feel it’s far better to get this right, than to rush it in with an error or two, or a mismatched thought. And, hopefully, there is another cycle :grinning_face:

Sorry I think I mislead you a bit, and I’m sorry about that. After thinking about this more and further discussions:

We can’t handle any more extensions in PostGIS core especially big ones. So it would be better to spin it off as a separate extension as I mentioned here - Hex9 Extension Draft PR by MrBenGriffin · Pull Request #863 · postgis/postgis · GitHub

The reason for this is because of security and technical debt. For the past few months, we’ve been bombarded with nothing but security hole notices discovered by AI bots and each major hole causes us to do a new release more frequent than we’d like. If we include your extension, which is fairly complicated, then we’d be on the hook to support it and continuously patch it forever as new security holes are discovered and since you are relatively new to us, we can’t be assured you would help out with that effort. So I think it’s best given the size of it, that it just be packaged separate from PostGIS as are other extensions:

pgRouting - GitHub - pgRouting/pgrouting: Repository contains pgRouting library. Development branch is "develop", stable branch is "master" · GitHub
MobilityDb - GitHub - MobilityDB/MobilityDB: MobilityDB is a geospatial trajectory data management & analysis platform, built on PostgreSQL and PostGIS. · GitHub
h3-pg GitHub - postgis/h3-pg: PostgreSQL bindings for H3, a hierarchical hexagonal geospatial indexing system · GitHub – this one though it’s in the PostGIS org, is not part of postgis core . It used to be in a separate org, but since a bunch of us worked on it, and the current maintainer could no longer support it given job changes, we took ownership of it.

In PostGIS 3.7.0, we removed address_standardizer and postgis_tiger_geocoder so these will now be shipped as separate from core too. Main reason is these had release cycles not inlined with PostGIS, so it was silly to keep on changing the version numbers of these when nothing changed. Also security issues in these would cause us to do another release even when nothing else in PostGIS changed.

These are still under PostGIS org, but not part of PostGIS core anymore:

The other benefit of having an extension outside of PostGIS core is you are not tied to our release cycle. That’s one of the reasons (aside from licensing incompatibility) that PostGIS is not part of the core PostgreSQL offering even though many people wanted it to be..So that we can work on our own release cycle.

Hi Regina,

That’s a fair concern, and I completely understand that the PostGIS team has been burdened by technical debt and abandoned contributions in the past. I have had similar experiences, albeit in a corporate environment.

I also appreciate the architectural shift you mentioned. Knowing that this is a structural policy change makes your team’s decision entirely understandable.

Regarding long-term assurance: as a volunteer, I can’t provide an absolute guarantee of my future availability. The most I can offer is my current commitment and my track record—I still actively maintain and support software I wrote as far back as 1998. I don’t tend to abandon tools I build. That said, I feel that, in general, trust in open source is built through ongoing participation rather than upfront promises.

In any case, I appreciate the discussion and the care you’re taking with PostGIS’s long-term health.

If my work has not earned its place in core, could PostGIS consider supporting it on PostGIS org as a contributed extension - especially with a clear caveat that this is contributor-maintained?

Kind regards

Ben

We generally don’t do that out of the gate. Best is to start on your own and see how much traction it gains. If I feel it’s stable enough I’ll start packaging it and try to encourage other packagers to do the same.
h3-pg was a special case for a couple of reasons:

  1. h3-pg had existed for a couple of years already and already packaged by pgdg packagers because the guy who managed it maintained it for many years on his own and clearly put a lot of effort into it.
  2. It had a fairly large user-base by the time we picked it up.
  3. A couple of us had clients already using it, so we already had so to speak an urgent need to keep it alive for client business.

So given your project is a relatively new project that hasn’t proven its metal and hasn’t been stress tested yet, its too early for that. But in a year or two, maybe. Also if you fix some issues in postgis from open tickets, you would gain more of the PostGIS core trust.

Another example is the GitHub - postgis/docker-postgis: Docker image for PostGIS · GitHub - none of us on the core team use docker for our production use, but the project had lived for like 10 years and garnered quite a huge following. So when the main maintainer could no longer support it, we were asked by the community to adopt it. We were a bit torn. But there were 2 strong heavy users of the project that were willing to do much of the heavy-lifting, one we knew cause he was already managing another postgis related project and hung around https://matrix.to/#/#postgis:osgeo.org the other guy it was clear he was doing a significant number of pull requests to the project. Even then it was pretty much a 50/50 for/against. I think that turned out pretty well even though we were close to saying no.