void _faceIjkToGeoBoundary()

in src/h3lib/lib/faceijk.c [672:773]


void _faceIjkToGeoBoundary(const FaceIJK* h, int res, int isPentagon,
                           GeoBoundary* g) {
    if (isPentagon) {
        _faceIjkPentToGeoBoundary(h, res, g);
        return;
    }

    int adjRes = res;
    FaceIJK centerIJK = *h;
    FaceIJK fijkVerts[NUM_HEX_VERTS];
    _faceIjkToVerts(&centerIJK, &adjRes, fijkVerts);

    // convert each vertex to lat/lon
    // adjust the face of each vertex as appropriate and introduce
    // edge-crossing vertices as needed
    g->numVerts = 0;
    int lastFace = -1;
    Overage lastOverage = NO_OVERAGE;
    for (int vert = 0; vert < NUM_HEX_VERTS + 1; vert++) {
        int v = vert % NUM_HEX_VERTS;

        FaceIJK fijk = fijkVerts[v];

        int pentLeading4 = 0;
        Overage overage = _adjustOverageClassII(&fijk, adjRes, pentLeading4, 1);

        /*
        Check for edge-crossing. Each face of the underlying icosahedron is a
        different projection plane. So if an edge of the hexagon crosses an
        icosahedron edge, an additional vertex must be introduced at that
        intersection point. Then each half of the cell edge can be projected
        to geographic coordinates using the appropriate icosahedron face
        projection. Note that Class II cell edges have vertices on the face
        edge, with no edge line intersections.
        */
        if (isResClassIII(res) && vert > 0 && fijk.face != lastFace &&
            lastOverage != FACE_EDGE) {
            // find hex2d of the two vertexes on original face
            int lastV = (v + 5) % NUM_HEX_VERTS;
            Vec2d orig2d0;
            _ijkToHex2d(&fijkVerts[lastV].coord, &orig2d0);

            Vec2d orig2d1;
            _ijkToHex2d(&fijkVerts[v].coord, &orig2d1);

            // find the appropriate icosa face edge vertexes
            int maxDim = maxDimByCIIres[adjRes];
            Vec2d v0 = {3.0 * maxDim, 0.0};
            Vec2d v1 = {-1.5 * maxDim, 3.0 * M_SQRT3_2 * maxDim};
            Vec2d v2 = {-1.5 * maxDim, -3.0 * M_SQRT3_2 * maxDim};

            int face2 = ((lastFace == centerIJK.face) ? fijk.face : lastFace);
            Vec2d* edge0;
            Vec2d* edge1;
            switch (adjacentFaceDir[centerIJK.face][face2]) {
                case IJ:
                    edge0 = &v0;
                    edge1 = &v1;
                    break;
                case JK:
                    edge0 = &v1;
                    edge1 = &v2;
                    break;
                case KI:
                default:
                    assert(adjacentFaceDir[centerIJK.face][face2] == KI);
                    edge0 = &v2;
                    edge1 = &v0;
                    break;
            }

            // find the intersection and add the lat/lon point to the result
            Vec2d inter;
            _v2dIntersect(&orig2d0, &orig2d1, edge0, edge1, &inter);
            /*
            If a point of intersection occurs at a hexagon vertex, then each
            adjacent hexagon edge will lie completely on a single icosahedron
            face, and no additional vertex is required.
            */
            bool isIntersectionAtVertex =
                _v2dEquals(&orig2d0, &inter) || _v2dEquals(&orig2d1, &inter);
            if (!isIntersectionAtVertex) {
                _hex2dToGeo(&inter, centerIJK.face, adjRes, 1,
                            &g->verts[g->numVerts]);
                g->numVerts++;
            }
        }

        // convert vertex to lat/lon and add to the result
        // vert == NUM_HEX_VERTS is only used to test for possible intersection
        // on last edge
        if (vert < NUM_HEX_VERTS) {
            Vec2d vec;
            _ijkToHex2d(&fijk.coord, &vec);
            _hex2dToGeo(&vec, fijk.face, adjRes, 1, &g->verts[g->numVerts]);
            g->numVerts++;
        }

        lastFace = fijk.face;
        lastOverage = overage;
    }
}