示例#1
0
        /// <summary>
        /// Generates the cell boundary in spherical coordinates for a pentagonal cell
        /// given by a FaceIJK address at a specified resolution.
        /// </summary>
        /// <param name="h">The FaceIJK address of the pentagonal cell.</param>
        /// <param name="res">The H3 resolution of the cell.</param>
        /// <param name="g">The spherical coordinates of the cell boundary.</param>
        /// <!-- Based off 3.1.1 -->
        public static void _faceIjkPentToGeoBoundary(ref FaceIJK h, int res, ref GeoBoundary g)
        {
            // the vertexes of an origin-centered pentagon in a Class II resolution on a
            // substrate grid with aperture sequence 33r. The aperture 3 gets us the
            // vertices, and the 3r gets us back to Class II.
            // vertices listed ccw from the i-axes
            CoordIJK[] vertsCII =
            {
                new CoordIJK(2, 1, 0), // 0
                new CoordIJK(1, 2, 0), // 1
                new CoordIJK(0, 2, 1), // 2
                new CoordIJK(0, 1, 2), // 3
                new CoordIJK(1, 0, 2)  // 4
            };

            // the vertexes of an origin-centered pentagon in a Class III resolution on
            // a substrate grid with aperture sequence 33r7r. The aperture 3 gets us the
            // vertices, and the 3r7r gets us to Class II. vertices listed ccw from the
            // i-axes
            CoordIJK[] vertsCIII =
            {
                new CoordIJK(5, 4, 0), // 0
                new CoordIJK(1, 5, 0), // 1
                new CoordIJK(0, 5, 4), // 2
                new CoordIJK(0, 1, 5), // 3
                new CoordIJK(4, 0, 5)  // 4
            };

            // get the correct set of substrate vertices for this resolution
            List <CoordIJK> verts = new List <CoordIJK>();

            verts = H3Index.isResClassIII(res)
                ? vertsCIII.ToList()
                : vertsCII.ToList();

            // adjust the center point to be in an aperture 33r substrate grid
            // these should be composed for speed
            FaceIJK centerIJK = new FaceIJK();

            centerIJK.face  = h.face;
            centerIJK.coord = new CoordIJK(h.coord.i, h.coord.j, h.coord.k);
            CoordIJK._downAp3(ref centerIJK.coord);
            CoordIJK._downAp3r(ref centerIJK.coord);

            // if res is Class III we need to add a cw aperture 7 to get to
            // icosahedral Class II
            int adjRes = res;

            if (H3Index.isResClassIII(res))
            {
                CoordIJK._downAp7r(ref centerIJK.coord);
                adjRes++;
            }

            // The center point is now in the same substrate grid as the origin
            // cell vertices. Add the center point substate coordinates
            // to each vertex to translate the vertices to that cell.
            FaceIJK[] fijkVerts = new FaceIJK[Constants.NUM_PENT_VERTS];
            for (int v = 0; v < Constants.NUM_PENT_VERTS; v++)
            {
                fijkVerts[v]      = new FaceIJK();
                fijkVerts[v].face = centerIJK.face;
                CoordIJK._ijkAdd(centerIJK.coord, verts[v], ref fijkVerts[v].coord);
                CoordIJK._ijkNormalize(ref fijkVerts[v].coord);
            }

            // convert each vertex to lat/lon
            // adjust the face of each vertex as appropriate and introduce
            // edge-crossing vertices as needed
            g.numVerts = 0;
            for (int i = 0; i < g.verts.Count; i++)
            {
                g.verts[i] = new GeoCoord();
            }
            FaceIJK lastFijk = new FaceIJK();

            for (int vert = 0; vert < Constants.NUM_PENT_VERTS + 1; vert++)
            {
                int v = vert % Constants.NUM_PENT_VERTS;

                FaceIJK fijk = fijkVerts[v];

                int pentLeading4 = 0;
                int overage      = _adjustOverageClassII(ref fijk, adjRes, pentLeading4, 1);
                if (overage == 2) // in a different triangle
                {
                    while (true)
                    {
                        overage = _adjustOverageClassII(ref fijk, adjRes, pentLeading4, 1);
                        if (overage != 2) // not in a different triangle
                        {
                            break;
                        }
                    }
                }

                // all Class III pentagon edges cross icosa edges
                // note that Class II pentagons have vertices on the edge,
                // not edge intersections
                if (H3Index.isResClassIII(res) && vert > 0)
                {
                    // find hex2d of the two vertexes on the last face

                    FaceIJK tmpFijk = new FaceIJK(fijk.face, new CoordIJK(fijk.coord.i, fijk.coord.j, fijk.coord.k));

                    Vec2d orig2d0 = new Vec2d();
                    CoordIJK._ijkToHex2d(lastFijk.coord, ref orig2d0);

                    int currentToLastDir = adjacentFaceDir[tmpFijk.face, lastFijk.face];

                    FaceOrientIJK fijkOrient =
                        new FaceOrientIJK(
                            faceNeighbors[tmpFijk.face, currentToLastDir].face,
                            faceNeighbors[tmpFijk.face, currentToLastDir].translate.i,
                            faceNeighbors[tmpFijk.face, currentToLastDir].translate.j,
                            faceNeighbors[tmpFijk.face, currentToLastDir].translate.k,
                            faceNeighbors[tmpFijk.face, currentToLastDir].ccwRot60
                            );

//                        faceNeighbors[tmpFijk.face,currentToLastDir];

                    tmpFijk.face = fijkOrient.face;
                    //CoordIJK ijk = tmpFijk.coord;
                    CoordIJK ijk = new CoordIJK(tmpFijk.coord.i, tmpFijk.coord.j, tmpFijk.coord.k);

                    // rotate and translate for adjacent face
                    for (int i = 0; i < fijkOrient.ccwRot60; i++)
                    {
                        CoordIJK._ijkRotate60ccw(ref ijk);
                    }

                    CoordIJK transVec = fijkOrient.translate;
                    CoordIJK._ijkScale(ref transVec, unitScaleByCIIres[adjRes] * 3);
                    CoordIJK._ijkAdd(ijk, transVec, ref ijk);
                    CoordIJK._ijkNormalize(ref ijk);

                    Vec2d orig2d1 = new Vec2d();
                    CoordIJK._ijkToHex2d(ijk, ref orig2d1);

                    // find the appropriate icosa face edge vertexes
                    int   maxDim = maxDimByCIIres[adjRes];
                    Vec2d v0     = new Vec2d(3.0 * maxDim, 0.0);
                    Vec2d v1     = new Vec2d(-1.5 * maxDim, 3.0 * Constants.M_SQRT3_2 * maxDim);
                    Vec2d v2     = new Vec2d(-1.5 * maxDim, -3.0 * Constants.M_SQRT3_2 * maxDim);

                    Vec2d edge0 = new Vec2d();
                    Vec2d edge1 = new Vec2d();
                    switch (adjacentFaceDir[tmpFijk.face, fijk.face])
                    {
                    case IJ:
                        edge0 = v0;
                        edge1 = v1;
                        break;

                    case JK:
                        edge0 = v1;
                        edge1 = v2;
                        break;

                    case KI:
                    default:
                        if (adjacentFaceDir[tmpFijk.face, fijk.face] != KI)
                        {
                            throw new Exception("assert(adjacentFaceDir[tmpFijk.face][fijk.face] == KI);");
                        }
                        edge0 = v2;
                        edge1 = v0;
                        break;
                    }

                    // find the intersection and add the lat/lon point to the result
                    Vec2d inter = new Vec2d();
                    Vec2d._v2dIntersect(orig2d0, orig2d1, edge0, edge1, ref inter);
                    var gnv = g.verts[g.numVerts];
                    _hex2dToGeo(ref inter, tmpFijk.face, adjRes, 1, ref gnv);
                    g.verts[g.numVerts] = gnv;
                    g.numVerts++;
                }

                // convert vertex to lat/lon and add to the result
                // vert == NUM_PENT_VERTS is only used to test for possible intersection
                // on last edge
                if (vert < Constants.NUM_PENT_VERTS)
                {
                    Vec2d vec = new Vec2d();
                    CoordIJK._ijkToHex2d(fijk.coord, ref vec);
                    var gnv = g.verts[g.numVerts];
                    _hex2dToGeo(ref vec, fijk.face, adjRes, 1, ref gnv);
                    g.verts[g.numVerts] = gnv;
                    g.numVerts++;
                }
                lastFijk = fijk;
            }
        }
示例#2
0
        /// <summary>
        /// Adjusts a FaceIJK address in place so that the resulting cell address is
        /// relative to the correct icosahedral face.
        /// </summary>
        /// <param name="fijk">The FaceIJK address of the cell.</param>
        /// <param name="res">The H3 resolution of the cell.</param>
        /// <param name="pentLeading4">Whether or not the cell is a pentagon with a leading digit 4</param>
        /// <param name="substrate">Whether or not the cell is in a substrate grid.</param>
        /// <returns>
        /// 0 if on original face (no overage); 1 if on face edge (only occurs
        /// on substrate grids); 2 if overage on new face interior
        /// </returns>
        /// <!-- Based off 3.1.1 -->
        public static int _adjustOverageClassII(ref FaceIJK fijk, int res, int pentLeading4, int substrate)
        {
            int overage = 0;

            CoordIJK ijk = new CoordIJK(fijk.coord.i, fijk.coord.j, fijk.coord.k);

            // get the maximum dimension value; scale if a substrate grid
            int maxDim = maxDimByCIIres[res];

            if (substrate != 0)
            {
                maxDim *= 3;
            }

            // check for overage
            if ((substrate != 0) && ijk.i + ijk.j + ijk.k == maxDim) // on edge
            {
                overage = 1;
            }
            else if (ijk.i + ijk.j + ijk.k > maxDim)  // overage
            {
                overage = 2;

                FaceOrientIJK fijkOrient = new FaceOrientIJK();
                if (ijk.k > 0)
                {
                    if (ijk.j > 0) // jk "quadrant"
                    {
                        //fijkOrient = faceNeighbors[fijk.face,JK];
                        fijkOrient = new FaceOrientIJK(
                            faceNeighbors[fijk.face, JK].face,
                            faceNeighbors[fijk.face, JK].translate.i,
                            faceNeighbors[fijk.face, JK].translate.j,
                            faceNeighbors[fijk.face, JK].translate.k,
                            faceNeighbors[fijk.face, JK].ccwRot60);
                    }
                    else  // ik "quadrant"
                    {
                        //fijkOrient = faceNeighbors[fijk.face,KI];
                        fijkOrient = new FaceOrientIJK(
                            faceNeighbors[fijk.face, KI].face,
                            faceNeighbors[fijk.face, KI].translate.i,
                            faceNeighbors[fijk.face, KI].translate.j,
                            faceNeighbors[fijk.face, KI].translate.k,
                            faceNeighbors[fijk.face, KI].ccwRot60);

                        // adjust for the pentagonal missing sequence
                        if (pentLeading4 != 0)
                        {
                            // translate origin to center of pentagon
                            CoordIJK origin = new CoordIJK();
                            CoordIJK._setIJK(ref origin, maxDim, 0, 0);
                            CoordIJK tmp = new CoordIJK();
                            CoordIJK._ijkSub(ref ijk, ref origin, ref tmp);
                            // rotate to adjust for the missing sequence
                            CoordIJK._ijkRotate60cw(ref tmp);
                            // translate the origin back to the center of the triangle
                            CoordIJK._ijkAdd(tmp, origin, ref ijk);
                        }
                    }
                }
                else // ij "quadrant"
                {
//                    fijkOrient = faceNeighbors[fijk.face,IJ];
                    fijkOrient = new FaceOrientIJK(
                        faceNeighbors[fijk.face, IJ].face,
                        faceNeighbors[fijk.face, IJ].translate.i,
                        faceNeighbors[fijk.face, IJ].translate.j,
                        faceNeighbors[fijk.face, IJ].translate.k,
                        faceNeighbors[fijk.face, IJ].ccwRot60);
                }

                fijk.face = fijkOrient.face;

                // rotate and translate for adjacent face
                for (int i = 0; i < fijkOrient.ccwRot60; i++)
                {
                    CoordIJK._ijkRotate60ccw(ref ijk);
                }

//                CoordIJK transVec = fijkOrient.translate;
                CoordIJK transVec = new CoordIJK
                                    (
                    fijkOrient.translate.i,
                    fijkOrient.translate.j,
                    fijkOrient.translate.k
                                    );
                int unitScale = unitScaleByCIIres[res];
                if (substrate != 0)
                {
                    unitScale *= 3;
                }
                CoordIJK._ijkScale(ref transVec, unitScale);
                CoordIJK._ijkAdd(ijk, transVec, ref ijk);
                CoordIJK._ijkNormalize(ref ijk);

                // overage points on pentagon boundaries can end up on edges
                if ((substrate != 0) && ijk.i + ijk.j + ijk.k == maxDim) // on edge
                {
                    overage = 1;
                }
            }

            fijk.coord = ijk;
            return(overage);
        }