in src/h3lib/lib/localij.c [131:264]
int h3ToLocalIjk(H3Index origin, H3Index h3, CoordIJK* out) {
int res = H3_GET_RESOLUTION(origin);
if (res != H3_GET_RESOLUTION(h3)) {
return 1;
}
int originBaseCell = H3_GET_BASE_CELL(origin);
int baseCell = H3_GET_BASE_CELL(h3);
// Direction from origin base cell to index base cell
Direction dir = CENTER_DIGIT;
Direction revDir = CENTER_DIGIT;
if (originBaseCell != baseCell) {
dir = _getBaseCellDirection(originBaseCell, baseCell);
if (dir == INVALID_DIGIT) {
// Base cells are not neighbors, can't unfold.
return 2;
}
revDir = _getBaseCellDirection(baseCell, originBaseCell);
assert(revDir != INVALID_DIGIT);
}
int originOnPent = _isBaseCellPentagon(originBaseCell);
int indexOnPent = _isBaseCellPentagon(baseCell);
FaceIJK indexFijk = {0};
if (dir != CENTER_DIGIT) {
// Rotate index into the orientation of the origin base cell.
// cw because we are undoing the rotation into that base cell.
int baseCellRotations = baseCellNeighbor60CCWRots[originBaseCell][dir];
if (indexOnPent) {
for (int i = 0; i < baseCellRotations; i++) {
h3 = _h3RotatePent60cw(h3);
revDir = _rotate60cw(revDir);
if (revDir == K_AXES_DIGIT) revDir = _rotate60cw(revDir);
}
} else {
for (int i = 0; i < baseCellRotations; i++) {
h3 = _h3Rotate60cw(h3);
revDir = _rotate60cw(revDir);
}
}
}
// Face is unused. This produces coordinates in base cell coordinate space.
_h3ToFaceIjkWithInitializedFijk(h3, &indexFijk);
if (dir != CENTER_DIGIT) {
assert(baseCell != originBaseCell);
assert(!(originOnPent && indexOnPent));
int pentagonRotations = 0;
int directionRotations = 0;
if (originOnPent) {
int originLeadingDigit = _h3LeadingNonZeroDigit(origin);
if (FAILED_DIRECTIONS[originLeadingDigit][dir]) {
// TODO: We may be unfolding the pentagon incorrectly in this
// case; return an error code until this is guaranteed to be
// correct.
return 3;
}
directionRotations = PENTAGON_ROTATIONS[originLeadingDigit][dir];
pentagonRotations = directionRotations;
} else if (indexOnPent) {
int indexLeadingDigit = _h3LeadingNonZeroDigit(h3);
if (FAILED_DIRECTIONS[indexLeadingDigit][revDir]) {
// TODO: We may be unfolding the pentagon incorrectly in this
// case; return an error code until this is guaranteed to be
// correct.
return 4;
}
pentagonRotations = PENTAGON_ROTATIONS[revDir][indexLeadingDigit];
}
assert(pentagonRotations >= 0);
assert(directionRotations >= 0);
for (int i = 0; i < pentagonRotations; i++) {
_ijkRotate60cw(&indexFijk.coord);
}
CoordIJK offset = {0};
_neighbor(&offset, dir);
// Scale offset based on resolution
for (int r = res - 1; r >= 0; r--) {
if (isResClassIII(r + 1)) {
// rotate ccw
_downAp7(&offset);
} else {
// rotate cw
_downAp7r(&offset);
}
}
for (int i = 0; i < directionRotations; i++) {
_ijkRotate60cw(&offset);
}
// Perform necessary translation
_ijkAdd(&indexFijk.coord, &offset, &indexFijk.coord);
_ijkNormalize(&indexFijk.coord);
} else if (originOnPent && indexOnPent) {
// If the origin and index are on pentagon, and we checked that the base
// cells are the same or neighboring, then they must be the same base
// cell.
assert(baseCell == originBaseCell);
int originLeadingDigit = _h3LeadingNonZeroDigit(origin);
int indexLeadingDigit = _h3LeadingNonZeroDigit(h3);
if (FAILED_DIRECTIONS[originLeadingDigit][indexLeadingDigit]) {
// TODO: We may be unfolding the pentagon incorrectly in this case;
// return an error code until this is guaranteed to be correct.
return 5;
}
int withinPentagonRotations =
PENTAGON_ROTATIONS[originLeadingDigit][indexLeadingDigit];
for (int i = 0; i < withinPentagonRotations; i++) {
_ijkRotate60cw(&indexFijk.coord);
}
}
*out = indexFijk.coord;
return 0;
}