Search code examples
hexagonal-tilesh3

H3 Cell gridDistance limitations


In the docs for gridDistance is the following sentence "Finding the distance can fail because the two indexes are not comparable (different resolutions), too far apart, or are separated by pentagonal distortion".

The different resolutions is fairly obvious, but I'm struggling to understand the other two exceptions. What exactly does "too far apart" mean? Distance in H3 cells or distance measured in KMs

Consider the following ...

function example1() {
  const cellA = '801bfffffffffff';         // base cell 13
  const cellB = '8035fffffffffff';         // base cell 26
  return h3.gridDistance(cellA , cellB);   // <--- distance 1
}

Those are two neighbouring Res0 cells, and griddistance returns 1...all good.

Now consider the following ...

function example2() {
  const cellA = '801bfffffffffff';         // base cell 13
  const cellC = '8055fffffffffff';         // base cell 42
  return h3.gridDistance(cellA , cellC);   // <--- error
}

cellC is a neighbour of cellB (but not a neighbour of cellA). To my eye this distance should just be 2, but instead an error is returned.

At first I thought that faces of the icosohedron might be coming into play as 801bfffffffffff straddles two icosohedron faces, but consider the next example...

function example3() {
  const cellA = '8019fffffffffff';         // base cell 12
  const cellC = '803bfffffffffff';         // base cell 29
  return h3.gridDistance(cellA , cellC);   // <--- error
}

Again, to my eye the distance should be 2, but an error is generated again. I suppose "too far apart" could mean distance in miles or kilometers, but this just doesn't feel right. As both cells in example3 are wholly contained in one icosohedron face, I don't understand how pentagonal distortion is at play.

Could someone please explain what I'm missing?

**Note: my actual application tries to get the distance between R7 cells that are not necessarily "close" to one another and regularly gets an error for gridDistance. This question is framed in terms of Res0 cells for clarity and illustration. **


Solution

  • The distance is calculated based on the "local" grid for each face of the icosahedron. The implementation is (very roughly) as follows:

    • If the two cells are on the same face of the icosahedron, calculate their distance on the grid using their IJK coordinates (axial coordinates for the grid)
    • If the two cells are on adjacent faces of the icosahedron, "unfold" the two faces and rotate the neighboring grid so that its axes align with the origin face. Now you have one unified grid for both faces, calculate the IJK distance.

    The problem arises if the two faces aren't neighbors - the "unfolding" step gets a lot harder and may not work correctly, as it has to traverse multiple faces. There's a separate but related problem when cells are on a pentagon base cell, and traversal may require stepping over multiple icosahedron edges (as each pentagon crosses 5 faces of the icosahedron).

    There isn't a fundamental reason why we can't calculate the distance, we just don't have an implementation that does it correctly in the failure cases. The "right" implementation is probably draw a great arc from A to B, take all of the hexagons at the intersection of the great arc and the icosahedron edges, and then do the piecewise distance between each pair, using only the local grids - it's just not implemented yet.

    So as far as the current API goes, the best we can offer is "H3 will do a good faith effort to calculate distance, but may fail, particularly for cells that are distant (in terms of degrees), because these may not fall on the same or neighboring faces."