in src/h3lib/lib/algos.c [284:412]
H3Index h3NeighborRotations(H3Index origin, Direction dir, int* rotations) {
H3Index out = origin;
for (int i = 0; i < *rotations; i++) {
dir = _rotate60ccw(dir);
}
int newRotations = 0;
int oldBaseCell = H3_GET_BASE_CELL(out);
Direction oldLeadingDigit = _h3LeadingNonZeroDigit(out);
// Adjust the indexing digits and, if needed, the base cell.
int r = H3_GET_RESOLUTION(out) - 1;
while (true) {
if (r == -1) {
H3_SET_BASE_CELL(out, baseCellNeighbors[oldBaseCell][dir]);
newRotations = baseCellNeighbor60CCWRots[oldBaseCell][dir];
if (H3_GET_BASE_CELL(out) == INVALID_BASE_CELL) {
// Adjust for the deleted k vertex at the base cell level.
// This edge actually borders a different neighbor.
H3_SET_BASE_CELL(out,
baseCellNeighbors[oldBaseCell][IK_AXES_DIGIT]);
newRotations =
baseCellNeighbor60CCWRots[oldBaseCell][IK_AXES_DIGIT];
// perform the adjustment for the k-subsequence we're skipping
// over.
out = _h3Rotate60ccw(out);
*rotations = *rotations + 1;
}
break;
} else {
Direction oldDigit = H3_GET_INDEX_DIGIT(out, r + 1);
Direction nextDir;
if (isResClassIII(r + 1)) {
H3_SET_INDEX_DIGIT(out, r + 1, NEW_DIGIT_II[oldDigit][dir]);
nextDir = NEW_ADJUSTMENT_II[oldDigit][dir];
} else {
H3_SET_INDEX_DIGIT(out, r + 1, NEW_DIGIT_III[oldDigit][dir]);
nextDir = NEW_ADJUSTMENT_III[oldDigit][dir];
}
if (nextDir != CENTER_DIGIT) {
dir = nextDir;
r--;
} else {
// No more adjustment to perform
break;
}
}
}
int newBaseCell = H3_GET_BASE_CELL(out);
if (_isBaseCellPentagon(newBaseCell)) {
int alreadyAdjustedKSubsequence = 0;
// force rotation out of missing k-axes sub-sequence
if (_h3LeadingNonZeroDigit(out) == K_AXES_DIGIT) {
if (oldBaseCell != newBaseCell) {
// in this case, we traversed into the deleted
// k subsequence of a pentagon base cell.
// We need to rotate out of that case depending
// on how we got here.
// check for a cw/ccw offset face; default is ccw
if (_baseCellIsCwOffset(
newBaseCell, baseCellData[oldBaseCell].homeFijk.face)) {
out = _h3Rotate60cw(out);
} else {
// See cwOffsetPent in testKRing.c for why this is
// unreachable.
out = _h3Rotate60ccw(out); // LCOV_EXCL_LINE
}
alreadyAdjustedKSubsequence = 1;
} else {
// In this case, we traversed into the deleted
// k subsequence from within the same pentagon
// base cell.
if (oldLeadingDigit == CENTER_DIGIT) {
// Undefined: the k direction is deleted from here
return H3_NULL;
} else if (oldLeadingDigit == JK_AXES_DIGIT) {
// Rotate out of the deleted k subsequence
// We also need an additional change to the direction we're
// moving in
out = _h3Rotate60ccw(out);
*rotations = *rotations + 1;
} else if (oldLeadingDigit == IK_AXES_DIGIT) {
// Rotate out of the deleted k subsequence
// We also need an additional change to the direction we're
// moving in
out = _h3Rotate60cw(out);
*rotations = *rotations + 5;
} else {
// Should never occur
return H3_NULL; // LCOV_EXCL_LINE
}
}
}
for (int i = 0; i < newRotations; i++) out = _h3RotatePent60ccw(out);
// Account for differing orientation of the base cells (this edge
// might not follow properties of some other edges.)
if (oldBaseCell != newBaseCell) {
if (_isBaseCellPolarPentagon(newBaseCell)) {
// 'polar' base cells behave differently because they have all
// i neighbors.
if (oldBaseCell != 118 && oldBaseCell != 8 &&
_h3LeadingNonZeroDigit(out) != JK_AXES_DIGIT) {
*rotations = *rotations + 1;
}
} else if (_h3LeadingNonZeroDigit(out) == IK_AXES_DIGIT &&
!alreadyAdjustedKSubsequence) {
// account for distortion introduced to the 5 neighbor by the
// deleted k subsequence.
*rotations = *rotations + 1;
}
}
} else {
for (int i = 0; i < newRotations; i++) out = _h3Rotate60ccw(out);
}
*rotations = (*rotations + newRotations) % 6;
return out;
}