示例#1
0
        /// <summary>
        /// Convert an FaceIJK address to the corresponding H3Index.
        /// </summary>
        /// <param name="fijk"> The FaceIJK address.</param>
        /// <param name="res">The cell resolution.</param>
        /// <returns>The encoded H3Index (or 0 on failure).</returns>
        /// <!-- Based off 3.1.1 -->
        public static H3Index _faceIjkToH3(ref FaceIJK fijk, int res)
        {
            // initialize the index
            H3Index h = H3_INIT;

            H3_SET_MODE(ref h, Constants.H3_HEXAGON_MODE);
            H3_SET_RESOLUTION(ref h, res);

            // check for res 0/base cell
            if (res == 0)
            {
                if (fijk.coord.i > BaseCells.MAX_FACE_COORD ||
                    fijk.coord.j > BaseCells.MAX_FACE_COORD ||
                    fijk.coord.k > BaseCells.MAX_FACE_COORD)
                {
                    // out of range input
                    return(H3_INVALID_INDEX);
                }

                H3_SET_BASE_CELL(ref h, BaseCells._faceIjkToBaseCell(fijk));
                return(h);
            }

            // we need to find the correct base cell FaceIJK for this H3 index;
            // start with the passed in face and resolution res ijk coordinates
            // in that face's coordinate system
            //FaceIJK fijkBC = new FaceIJK(fijk.face, fijk.coord);
            FaceIJK fijkBC = new FaceIJK(fijk.face, new CoordIJK(fijk.coord.i, fijk.coord.j, fijk.coord.k));

            // build the H3Index from finest res up
            // adjust r for the fact that the res 0 base cell offsets the indexing digits
            CoordIJK ijk = fijkBC.coord;

            for (int r = res - 1; r >= 0; r--)
            {
                //CoordIJK lastIJK = ijk;
                CoordIJK lastIJK    = new CoordIJK(ijk.i, ijk.j, ijk.k);
                CoordIJK lastCenter = new CoordIJK();
                if (isResClassIII(r + 1))
                {
                    // rotate ccw
                    CoordIJK._upAp7(ref ijk);
                    lastCenter.i = ijk.i;
                    lastCenter.j = ijk.j;
                    lastCenter.k = ijk.k;
                    CoordIJK._downAp7(ref lastCenter);
                }
                else
                {
                    // rotate cw
                    CoordIJK._upAp7r(ref ijk);
                    lastCenter.i = ijk.i;
                    lastCenter.j = ijk.j;
                    lastCenter.k = ijk.k;
                    CoordIJK._downAp7r(ref lastCenter);
                }

                CoordIJK diff = new CoordIJK();
                CoordIJK._ijkSub(ref lastIJK, ref lastCenter, ref diff);
                CoordIJK._ijkNormalize(ref diff);

                H3_SET_INDEX_DIGIT(ref h, r + 1,
                                   (ulong)CoordIJK._unitIjkToDigit(ref diff));
            }

            // fijkBC should now hold the IJK of the base cell in the
            // coordinate system of the current face
            if (fijkBC.coord.i > BaseCells.MAX_FACE_COORD ||
                fijkBC.coord.j > BaseCells.MAX_FACE_COORD ||
                fijkBC.coord.k > BaseCells.MAX_FACE_COORD)
            {
                // out of range input
                return(H3_INVALID_INDEX);
            }

            // lookup the correct base cell
            int baseCell = BaseCells._faceIjkToBaseCell(fijkBC);

            H3_SET_BASE_CELL(ref h, baseCell);

            // rotate if necessary to get canonical base cell orientation
            // for this base cell
            int numRots = BaseCells._faceIjkToBaseCellCCWrot60(fijkBC);

            if (BaseCells._isBaseCellPentagon(baseCell))
            {
                // force rotation out of missing k-axes sub-sequence
                if (_h3LeadingNonZeroDigit(h) == Direction.K_AXES_DIGIT)
                {
                    // check for a cw/ccw offset face; default is ccw
                    if (BaseCells._baseCellIsCwOffset(baseCell, fijkBC.face))
                    {
                        h = _h3Rotate60cw(ref h);
                    }
                    else
                    {
                        h = _h3Rotate60ccw(ref h);
                    }
                }

                for (int i = 0; i < numRots; i++)
                {
                    h = _h3RotatePent60ccw(ref h);
                }
            }
            else
            {
                for (int i = 0; i < numRots; i++)
                {
                    h = _h3Rotate60ccw(ref h);
                }
            }

            return(h);
        }
示例#2
0
        /// <summary>
        /// Produces an index for ijk+ coordinates anchored by an origin.
        ///
        /// The coordinate space used by this function may have deleted
        /// regions or warping due to pentagonal distortion.
        ///
        /// Failure may occur if the coordinates are too far away from the origin
        /// or if the index is on the other side of a pentagon.
        /// </summary>
        /// <param name="origin">An anchoring index for the ijk+ coordinate system.</param>
        /// <param name="ijk">IJK+ Coordinates to find the index of</param>
        /// <param name="out_h3">The index will be placed here on success</param>
        /// <returns>0 on success, or another value on failure</returns>
        /// <!-- Based off 3.2.0 -->
        internal static int localIjkToH3(H3Index origin, CoordIJK ijk, ref H3Index out_h3)
        {
            int res            = H3Index.H3_GET_RESOLUTION(origin);
            int originBaseCell = H3Index.H3_GET_BASE_CELL(origin);
            int originOnPent   = BaseCells._isBaseCellPentagon(originBaseCell)
                                   ? 1
                                   : 0;

            // This logic is very similar to faceIjkToH3
            // initialize the index
            out_h3 = H3Index.H3_INIT;
            H3Index.H3_SET_MODE(ref out_h3, Constants.H3_HEXAGON_MODE);
            H3Index.H3_SET_RESOLUTION(ref out_h3, res);
            Direction dir;

            // check for res 0/base cell
            if (res == 0)
            {
                if (ijk.i > 1 || ijk.j > 1 || ijk.k > 1)
                {
                    // out of range input
                    return(1);
                }

                dir = CoordIJK._unitIjkToDigit(ref ijk);
                int newBaseCell = BaseCells._getBaseCellNeighbor(originBaseCell, dir);
                if (newBaseCell == BaseCells.INVALID_BASE_CELL)
                {
                    // Moving in an invalid direction off a pentagon.
                    return(1);
                }

                H3Index.H3_SET_BASE_CELL(ref out_h3, newBaseCell);
                return(0);
            }

            // we need to find the correct base cell offset (if any) for this H3 index;
            // start with the passed in base cell and resolution res ijk coordinates
            // in that base cell's coordinate system
            CoordIJK ijkCopy = new CoordIJK(ijk.i, ijk.j, ijk.k);

            // build the H3Index from finest res up
            // adjust r for the fact that the res 0 base cell offsets the indexing
            // digits
            for (int r = res - 1; r >= 0; r--)
            {
                CoordIJK lastIJK = ijkCopy;
                CoordIJK lastCenter;
                if (H3Index.isResClassIII(r + 1))
                {
                    // rotate ccw
                    CoordIJK._upAp7(ref ijkCopy);
                    lastCenter = ijkCopy;
                    CoordIJK._downAp7(ref lastCenter);
                }
                else
                {
                    // rotate cw
                    CoordIJK._upAp7r(ref ijkCopy);
                    lastCenter = ijkCopy;
                    CoordIJK._downAp7r(ref lastCenter);
                }

                CoordIJK diff = new CoordIJK();
                CoordIJK._ijkSub(ref lastIJK, ref lastCenter, ref diff);
                CoordIJK._ijkNormalize(ref diff);

                H3Index.H3_SET_INDEX_DIGIT(ref out_h3, r + 1, (ulong)CoordIJK._unitIjkToDigit(ref diff));
            }

            // ijkCopy should now hold the IJK of the base cell in the
            // coordinate system of the current base cell

            if (ijkCopy.i > 1 || ijkCopy.j > 1 || ijkCopy.k > 1)
            {
                // out of range input
                return(2);
            }

            // lookup the correct base cell
            dir = CoordIJK._unitIjkToDigit(ref ijkCopy);
            int baseCell = BaseCells._getBaseCellNeighbor(originBaseCell, dir);
            // If baseCell is invalid, it must be because the origin base cell is a
            // pentagon, and because pentagon base cells do not border each other,
            // baseCell must not be a pentagon.
            int indexOnPent =
                (baseCell == BaseCells.INVALID_BASE_CELL
                     ? 0
                     : BaseCells._isBaseCellPentagon(baseCell)
                         ? 1
                         : 0);

            if (dir != (int)Direction.CENTER_DIGIT)
            {
                // If the index is in a warped direction, we need to unwarp the base
                // cell direction. There may be further need to rotate the index digits.
                int pentagonRotations = 0;
                if (originOnPent != 0)
                {
                    Direction originLeadingDigit = H3Index._h3LeadingNonZeroDigit(origin);
                    pentagonRotations =
                        PENTAGON_ROTATIONS_REVERSE[(int)originLeadingDigit, (int)dir];
                    for (int i = 0; i < pentagonRotations; i++)
                    {
                        dir = CoordIJK._rotate60ccw(dir);
                    }

                    // The pentagon rotations are being chosen so that dir is not the
                    // deleted direction. If it still happens, it means we're moving
                    // into a deleted subsequence, so there is no index here.
                    if (dir == Direction.K_AXES_DIGIT)
                    {
                        return(3);
                    }

                    baseCell = BaseCells._getBaseCellNeighbor(originBaseCell, dir);

                    // indexOnPent does not need to be checked again since no pentagon
                    // base cells border each other.
                    if (baseCell == BaseCells.INVALID_BASE_CELL)
                    {
                        throw new Exception("assert(baseCell != BaseCells.INVALID_BASE_CELL);");
                    }

                    if (BaseCells._isBaseCellPolarPentagon(baseCell))
                    {
                        throw new Exception("assert(!BaseCells._isBaseCellPentagon(baseCell));");
                    }
                }

                // Now we can determine the relation between the origin and target base
                // cell.
                int baseCellRotations =
                    BaseCells.baseCellNeighbor60CCWRots[originBaseCell, (int)dir];
                if (baseCellRotations < 0)
                {
                    throw new Exception("assert(baseCellRotations >= 0);");
                }

                // Adjust for pentagon warping within the base cell. The base cell
                // should be in the right location, so now we need to rotate the index
                // back. We might not need to check for errors since we would just be
                // double mapping.
                if (indexOnPent != 0)
                {
                    Direction revDir =
                        BaseCells._getBaseCellDirection(baseCell, originBaseCell);

                    if (revDir == Direction.INVALID_DIGIT)
                    {
                        throw new Exception("assert(revDir != Direction.INVALID_DIGIT);");
                    }


                    // Adjust for the different coordinate space in the two base cells.
                    // This is done first because we need to do the pentagon rotations
                    // based on the leading digit in the pentagon's coordinate system.
                    for (int i = 0; i < baseCellRotations; i++)
                    {
                        out_h3 = H3Index._h3Rotate60ccw(ref out_h3);
                    }

                    Direction indexLeadingDigit = H3Index._h3LeadingNonZeroDigit(out_h3);
                    if (BaseCells._isBaseCellPolarPentagon(baseCell))
                    {
                        pentagonRotations =
                            PENTAGON_ROTATIONS_REVERSE_POLAR[(int)revDir, (int)indexLeadingDigit];
                    }
                    else
                    {
                        pentagonRotations =
                            PENTAGON_ROTATIONS_REVERSE_NONPOLAR[(int)revDir, (int)indexLeadingDigit];
                    }

                    if (pentagonRotations < 0)
                    {
                        throw new Exception("assert(pentagonRotations >= 0);");
                    }


                    for (int i = 0; i < pentagonRotations; i++)
                    {
                        out_h3 = H3Index._h3RotatePent60ccw(ref out_h3);
                    }
                }
                else
                {
                    if (pentagonRotations < 0)
                    {
                        throw new Exception("assert(pentagonRotations >= 0);");
                    }


                    for (int i = 0; i < pentagonRotations; i++)
                    {
                        out_h3 = H3Index._h3Rotate60ccw(ref out_h3);
                    }

                    // Adjust for the different coordinate space in the two base cells.
                    for (int i = 0; i < baseCellRotations; i++)
                    {
                        out_h3 = H3Index._h3Rotate60ccw(ref out_h3);
                    }
                }
            }
            else if (originOnPent != 0 && indexOnPent != 0)
            {
                int originLeadingDigit = (int)H3Index._h3LeadingNonZeroDigit(origin);
                int indexLeadingDigit  = (int)H3Index._h3LeadingNonZeroDigit(out_h3);

                int withinPentagonRotations =
                    PENTAGON_ROTATIONS_REVERSE[originLeadingDigit, indexLeadingDigit];
                if (withinPentagonRotations < 0)
                {
                    throw new Exception("assert(withinPentagonRotations >= 0);");
                }

                for (int i = 0; i < withinPentagonRotations; i++)
                {
                    out_h3 = H3Index._h3Rotate60ccw(ref out_h3);
                }
            }

            if (indexOnPent != 0)
            {
                // TODO: There are cases in h3ToLocalIjk which are failed but not
                // accounted for here - instead just fail if the recovered index is
                // invalid.
                if (H3Index._h3LeadingNonZeroDigit(out_h3) == Direction.K_AXES_DIGIT)
                {
                    return(4);
                }
            }

            H3Index.H3_SET_BASE_CELL(ref out_h3, baseCell);

            return(0);
        }
示例#3
0
        /// <summary>
        /// Convert an H3Index to a FaceIJK address.
        /// </summary>
        /// <param name="h"> The H3Index.</param>
        /// <param name="fijk"> The corresponding FaceIJK address.</param>
        /// <!-- Based off 3.1.1 -->
        public static void _h3ToFaceIjk(H3Index h, ref FaceIJK fijk)
        {
            int baseCell = H3_GET_BASE_CELL(h);

            // adjust for the pentagonal missing sequence; all of sub-sequence 5 needs
            // to be adjusted (and some of sub-sequence 4 below)
            if (BaseCells._isBaseCellPentagon(baseCell) && _h3LeadingNonZeroDigit(h) == Direction.IK_AXES_DIGIT)
            {
                h = _h3Rotate60cw(ref h);
            }

            // start with the "home" face and ijk+ coordinates for the base cell of c
            fijk = new FaceIJK(
                BaseCells.baseCellData[baseCell].homeFijk.face,
                new CoordIJK(
                    BaseCells.baseCellData[baseCell].homeFijk.coord.i,
                    BaseCells.baseCellData[baseCell].homeFijk.coord.j,
                    BaseCells.baseCellData[baseCell].homeFijk.coord.k
                    )
                );
            //fijk = BaseCells.baseCellData[baseCell].homeFijk;
            if (_h3ToFaceIjkWithInitializedFijk(h, ref fijk) == 0)
            {
                return; // no overage is possible; h lies on this face
            }

            // if we're here we have the potential for an "overage"; i.e., it is
            // possible that c lies on an adjacent face
            CoordIJK origIJK = new CoordIJK(fijk.coord.i, fijk.coord.j, fijk.coord.k);

            // if we're in Class III, drop into the next finer Class II grid
            int res = H3_GET_RESOLUTION(h);

            if (isResClassIII(res))
            {
                // Class III
                CoordIJK._downAp7r(ref fijk.coord);
                res++;
            }

            // adjust for overage if needed
            // a pentagon base cell with a leading 4 digit requires special handling
            bool pentLeading4 =
                (BaseCells._isBaseCellPentagon(baseCell) && _h3LeadingNonZeroDigit(h) == Direction.I_AXES_DIGIT);

            if (FaceIJK._adjustOverageClassII(ref fijk, res, pentLeading4 ? 1 : 0, 0) > 0)
            {
                // if the base cell is a pentagon we have the potential for secondary
                // overages
                if (BaseCells._isBaseCellPentagon(baseCell))
                {
                    while (true)
                    {
                        if (FaceIJK._adjustOverageClassII(ref fijk, res, 0, 0) == 0)
                        {
                            break;
                        }
                    }
                }

                if (res != H3_GET_RESOLUTION(h))
                {
                    CoordIJK._upAp7r(ref fijk.coord);
                }
            }
            else if (res != H3_GET_RESOLUTION(h))
            {
                fijk.coord = new CoordIJK(origIJK.i, origIJK.j, origIJK.k);
            }
        }