|  | @@ -417,43 +417,64 @@ final class FaceIJK {
 | 
	
		
			
				|  |  |       * for this FaceIJK address at a specified resolution.
 | 
	
		
			
				|  |  |       *
 | 
	
		
			
				|  |  |       * @param res    The H3 resolution of the cell.
 | 
	
		
			
				|  |  | -     * @param start  The first topological vertex to return.
 | 
	
		
			
				|  |  | -     * @param length The number of topological vertexes to return.
 | 
	
		
			
				|  |  |       */
 | 
	
		
			
				|  |  | -    public CellBoundary faceIjkPentToCellBoundary(int res, int start, int length) {
 | 
	
		
			
				|  |  | +    public CellBoundary faceIjkPentToCellBoundary(int res) {
 | 
	
		
			
				|  |  |          // adjust the center point to be in an aperture 33r substrate grid
 | 
	
		
			
				|  |  |          // these should be composed for speed
 | 
	
		
			
				|  |  |          this.coord.downAp3();
 | 
	
		
			
				|  |  |          this.coord.downAp3r();
 | 
	
		
			
				|  |  |          // if res is Class III we need to add a cw aperture 7 to get to
 | 
	
		
			
				|  |  |          // icosahedral Class II
 | 
	
		
			
				|  |  | -        int adjRes = res;
 | 
	
		
			
				|  |  | -        if (H3Index.isResolutionClassIII(res)) {
 | 
	
		
			
				|  |  | -            this.coord.downAp7r();
 | 
	
		
			
				|  |  | -            adjRes += 1;
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | +        final int adjRes = adjustRes(this.coord, res);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |          // If we're returning the entire loop, we need one more iteration in case
 | 
	
		
			
				|  |  |          // of a distortion vertex on the last edge
 | 
	
		
			
				|  |  | -        final int additionalIteration = length == Constants.NUM_PENT_VERTS ? 1 : 0;
 | 
	
		
			
				|  |  | -        final boolean isResolutionClassIII = H3Index.isResolutionClassIII(res);
 | 
	
		
			
				|  |  | -        // convert each vertex to lat/lng
 | 
	
		
			
				|  |  | -        // adjust the face of each vertex as appropriate and introduce
 | 
	
		
			
				|  |  | -        // edge-crossing vertices as needed
 | 
	
		
			
				|  |  | +        if (H3Index.isResolutionClassIII(res)) {
 | 
	
		
			
				|  |  | +            return faceIjkPentToCellBoundaryClassIII(adjRes);
 | 
	
		
			
				|  |  | +        } else {
 | 
	
		
			
				|  |  | +            return faceIjkPentToCellBoundaryClassII(adjRes);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    private CellBoundary faceIjkPentToCellBoundaryClassII(int adjRes) {
 | 
	
		
			
				|  |  | +        final LatLng[] points = new LatLng[Constants.NUM_PENT_VERTS];
 | 
	
		
			
				|  |  | +        final FaceIJK fijk = new FaceIJK(this.face, new CoordIJK(0, 0, 0));
 | 
	
		
			
				|  |  | +        for (int vert = 0; vert < Constants.NUM_PENT_VERTS; vert++) {
 | 
	
		
			
				|  |  | +            // 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.
 | 
	
		
			
				|  |  | +            fijk.coord.reset(
 | 
	
		
			
				|  |  | +                VERTEX_CLASSII[vert][0] + this.coord.i,
 | 
	
		
			
				|  |  | +                VERTEX_CLASSII[vert][1] + this.coord.j,
 | 
	
		
			
				|  |  | +                VERTEX_CLASSII[vert][2] + this.coord.k
 | 
	
		
			
				|  |  | +            );
 | 
	
		
			
				|  |  | +            fijk.coord.ijkNormalize();
 | 
	
		
			
				|  |  | +            fijk.face = this.face;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            fijk.adjustPentVertOverage(adjRes);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            points[vert] = fijk.coord.ijkToGeo(fijk.face, adjRes, true);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        return new CellBoundary(points, Constants.NUM_PENT_VERTS);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    private CellBoundary faceIjkPentToCellBoundaryClassIII(int adjRes) {
 | 
	
		
			
				|  |  |          final LatLng[] points = new LatLng[CellBoundary.MAX_CELL_BNDRY_VERTS];
 | 
	
		
			
				|  |  |          int numPoints = 0;
 | 
	
		
			
				|  |  | -        final CoordIJK scratch = new CoordIJK(0, 0, 0);
 | 
	
		
			
				|  |  | -        final FaceIJK fijk = new FaceIJK(this.face, scratch);
 | 
	
		
			
				|  |  | -        final int[][] coord = isResolutionClassIII ? VERTEX_CLASSIII : VERTEX_CLASSII;
 | 
	
		
			
				|  |  | +        final FaceIJK fijk = new FaceIJK(this.face, new CoordIJK(0, 0, 0));
 | 
	
		
			
				|  |  |          final CoordIJK lastCoord = new CoordIJK(0, 0, 0);
 | 
	
		
			
				|  |  |          int lastFace = this.face;
 | 
	
		
			
				|  |  | -        for (int vert = start; vert < start + length + additionalIteration; vert++) {
 | 
	
		
			
				|  |  | +        for (int vert = 0; vert < Constants.NUM_PENT_VERTS + 1; vert++) {
 | 
	
		
			
				|  |  |              final int v = vert % Constants.NUM_PENT_VERTS;
 | 
	
		
			
				|  |  |              // 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.
 | 
	
		
			
				|  |  | -            scratch.reset(coord[v][0], coord[v][1], coord[v][2]);
 | 
	
		
			
				|  |  | -            scratch.ijkAdd(this.coord.i, this.coord.j, this.coord.k);
 | 
	
		
			
				|  |  | -            scratch.ijkNormalize();
 | 
	
		
			
				|  |  | +            fijk.coord.reset(
 | 
	
		
			
				|  |  | +                VERTEX_CLASSIII[v][0] + this.coord.i,
 | 
	
		
			
				|  |  | +                VERTEX_CLASSIII[v][1] + this.coord.j,
 | 
	
		
			
				|  |  | +                VERTEX_CLASSIII[v][2] + this.coord.k
 | 
	
		
			
				|  |  | +            );
 | 
	
		
			
				|  |  | +            fijk.coord.ijkNormalize();
 | 
	
		
			
				|  |  |              fijk.face = this.face;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              fijk.adjustPentVertOverage(adjRes);
 | 
	
	
		
			
				|  | @@ -461,7 +482,7 @@ final class FaceIJK {
 | 
	
		
			
				|  |  |              // all Class III pentagon edges cross icosa edges
 | 
	
		
			
				|  |  |              // note that Class II pentagons have vertices on the edge,
 | 
	
		
			
				|  |  |              // not edge intersections
 | 
	
		
			
				|  |  | -            if (isResolutionClassIII && vert > start) {
 | 
	
		
			
				|  |  | +            if (vert > 0) {
 | 
	
		
			
				|  |  |                  // find hex2d of the two vertexes on the last face
 | 
	
		
			
				|  |  |                  final Vec2d orig2d0 = lastCoord.ijkToHex2d();
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -480,35 +501,17 @@ final class FaceIJK {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                  final Vec2d orig2d1 = lastCoord.ijkToHex2d();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                // find the appropriate icosa face edge vertexes
 | 
	
		
			
				|  |  | -                final Vec2d edge0;
 | 
	
		
			
				|  |  | -                final Vec2d edge1;
 | 
	
		
			
				|  |  | -                switch (adjacentFaceDir[fijkOrient.face][fijk.face]) {
 | 
	
		
			
				|  |  | -                    case IJ -> {
 | 
	
		
			
				|  |  | -                        edge0 = maxDimByCIIVec2d[adjRes][0];
 | 
	
		
			
				|  |  | -                        edge1 = maxDimByCIIVec2d[adjRes][1];
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | -                    case JK -> {
 | 
	
		
			
				|  |  | -                        edge0 = maxDimByCIIVec2d[adjRes][1];
 | 
	
		
			
				|  |  | -                        edge1 = maxDimByCIIVec2d[adjRes][2];
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | -                    // case KI:
 | 
	
		
			
				|  |  | -                    default -> {
 | 
	
		
			
				|  |  | -                        assert (adjacentFaceDir[fijkOrient.face][fijk.face] == KI);
 | 
	
		
			
				|  |  | -                        edge0 = maxDimByCIIVec2d[adjRes][2];
 | 
	
		
			
				|  |  | -                        edge1 = maxDimByCIIVec2d[adjRes][0];
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |                  // find the intersection and add the lat/lng point to the result
 | 
	
		
			
				|  |  | -                final Vec2d inter = Vec2d.v2dIntersect(orig2d0, orig2d1, edge0, edge1);
 | 
	
		
			
				|  |  | -                points[numPoints++] = inter.hex2dToGeo(fijkOrient.face, adjRes, true);
 | 
	
		
			
				|  |  | +                final Vec2d inter = findIntersectionPoint(orig2d0, orig2d1, adjRes, adjacentFaceDir[fijkOrient.face][fijk.face]);
 | 
	
		
			
				|  |  | +                if (inter != null) {
 | 
	
		
			
				|  |  | +                    points[numPoints++] = inter.hex2dToGeo(fijkOrient.face, adjRes, true);
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              // convert vertex to lat/lng and add to the result
 | 
	
		
			
				|  |  |              // vert == start + NUM_PENT_VERTS is only used to test for possible
 | 
	
		
			
				|  |  |              // intersection on last edge
 | 
	
		
			
				|  |  | -            if (vert < start + Constants.NUM_PENT_VERTS) {
 | 
	
		
			
				|  |  | +            if (vert < Constants.NUM_PENT_VERTS) {
 | 
	
		
			
				|  |  |                  points[numPoints++] = fijk.coord.ijkToGeo(fijk.face, adjRes, true);
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |              lastFace = fijk.face;
 | 
	
	
		
			
				|  | @@ -522,10 +525,8 @@ final class FaceIJK {
 | 
	
		
			
				|  |  |       * FaceIJK address at a specified resolution.
 | 
	
		
			
				|  |  |       *
 | 
	
		
			
				|  |  |       * @param res    The H3 resolution of the cell.
 | 
	
		
			
				|  |  | -     * @param start  The first topological vertex to return.
 | 
	
		
			
				|  |  | -     * @param length The number of topological vertexes to return.
 | 
	
		
			
				|  |  |       */
 | 
	
		
			
				|  |  | -    public CellBoundary faceIjkToCellBoundary(final int res, final int start, final int length) {
 | 
	
		
			
				|  |  | +    public CellBoundary faceIjkToCellBoundary(final int res) {
 | 
	
		
			
				|  |  |          // adjust the center point to be in an aperture 33r substrate grid
 | 
	
		
			
				|  |  |          // these should be composed for speed
 | 
	
		
			
				|  |  |          this.coord.downAp3();
 | 
	
	
		
			
				|  | @@ -533,32 +534,63 @@ final class FaceIJK {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          // if res is Class III we need to add a cw aperture 7 to get to
 | 
	
		
			
				|  |  |          // icosahedral Class II
 | 
	
		
			
				|  |  | -        int adjRes = res;
 | 
	
		
			
				|  |  | -        if (H3Index.isResolutionClassIII(res)) {
 | 
	
		
			
				|  |  | -            this.coord.downAp7r();
 | 
	
		
			
				|  |  | -            adjRes += 1;
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | +        final int adjRes = adjustRes(this.coord, res);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        // If we're returning the entire loop, we need one more iteration in case
 | 
	
		
			
				|  |  | -        // of a distortion vertex on the last edge
 | 
	
		
			
				|  |  | -        final int additionalIteration = length == Constants.NUM_HEX_VERTS ? 1 : 0;
 | 
	
		
			
				|  |  | -        final boolean isResolutionClassIII = H3Index.isResolutionClassIII(res);
 | 
	
		
			
				|  |  |          // convert each vertex to lat/lng
 | 
	
		
			
				|  |  |          // adjust the face of each vertex as appropriate and introduce
 | 
	
		
			
				|  |  |          // edge-crossing vertices as needed
 | 
	
		
			
				|  |  | +        if (H3Index.isResolutionClassIII(res)) {
 | 
	
		
			
				|  |  | +            return faceIjkToCellBoundaryClassIII(adjRes);
 | 
	
		
			
				|  |  | +        } else {
 | 
	
		
			
				|  |  | +            return faceIjkToCellBoundaryClassII(adjRes);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    private static int adjustRes(CoordIJK coord, int res) {
 | 
	
		
			
				|  |  | +        if (H3Index.isResolutionClassIII(res)) {
 | 
	
		
			
				|  |  | +            coord.downAp7r();
 | 
	
		
			
				|  |  | +            res += 1;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        return res;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    private CellBoundary faceIjkToCellBoundaryClassII(int adjRes) {
 | 
	
		
			
				|  |  | +        final LatLng[] points = new LatLng[Constants.NUM_HEX_VERTS];
 | 
	
		
			
				|  |  | +        final FaceIJK fijk = new FaceIJK(this.face, new CoordIJK(0, 0, 0));
 | 
	
		
			
				|  |  | +        for (int vert = 0; vert < Constants.NUM_HEX_VERTS; vert++) {
 | 
	
		
			
				|  |  | +            fijk.coord.reset(
 | 
	
		
			
				|  |  | +                VERTEX_CLASSII[vert][0] + this.coord.i,
 | 
	
		
			
				|  |  | +                VERTEX_CLASSII[vert][1] + this.coord.j,
 | 
	
		
			
				|  |  | +                VERTEX_CLASSII[vert][2] + this.coord.k
 | 
	
		
			
				|  |  | +            );
 | 
	
		
			
				|  |  | +            fijk.coord.ijkNormalize();
 | 
	
		
			
				|  |  | +            fijk.face = this.face;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            fijk.adjustOverageClassII(adjRes, false, true);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            // convert vertex to lat/lng and add to the result
 | 
	
		
			
				|  |  | +            // vert == start + NUM_HEX_VERTS is only used to test for possible
 | 
	
		
			
				|  |  | +            // intersection on last edge
 | 
	
		
			
				|  |  | +            points[vert] = fijk.coord.ijkToGeo(fijk.face, adjRes, true);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        return new CellBoundary(points, Constants.NUM_HEX_VERTS);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    private CellBoundary faceIjkToCellBoundaryClassIII(int adjRes) {
 | 
	
		
			
				|  |  |          final LatLng[] points = new LatLng[CellBoundary.MAX_CELL_BNDRY_VERTS];
 | 
	
		
			
				|  |  |          int numPoints = 0;
 | 
	
		
			
				|  |  | -        final CoordIJK scratch1 = new CoordIJK(0, 0, 0);
 | 
	
		
			
				|  |  | -        final FaceIJK fijk = new FaceIJK(this.face, scratch1);
 | 
	
		
			
				|  |  | -        final CoordIJK scratch2 = isResolutionClassIII ? new CoordIJK(0, 0, 0) : null;
 | 
	
		
			
				|  |  | -        final int[][] verts = isResolutionClassIII ? VERTEX_CLASSIII : VERTEX_CLASSII;
 | 
	
		
			
				|  |  | +        final FaceIJK fijk = new FaceIJK(this.face, new CoordIJK(0, 0, 0));
 | 
	
		
			
				|  |  | +        final CoordIJK scratch = new CoordIJK(0, 0, 0);
 | 
	
		
			
				|  |  |          int lastFace = -1;
 | 
	
		
			
				|  |  |          Overage lastOverage = Overage.NO_OVERAGE;
 | 
	
		
			
				|  |  | -        for (int vert = start; vert < start + length + additionalIteration; vert++) {
 | 
	
		
			
				|  |  | -            int v = vert % Constants.NUM_HEX_VERTS;
 | 
	
		
			
				|  |  | -            scratch1.reset(verts[v][0], verts[v][1], verts[v][2]);
 | 
	
		
			
				|  |  | -            scratch1.ijkAdd(this.coord.i, this.coord.j, this.coord.k);
 | 
	
		
			
				|  |  | -            scratch1.ijkNormalize();
 | 
	
		
			
				|  |  | +        for (int vert = 0; vert < Constants.NUM_HEX_VERTS + 1; vert++) {
 | 
	
		
			
				|  |  | +            final int v = vert % Constants.NUM_HEX_VERTS;
 | 
	
		
			
				|  |  | +            fijk.coord.reset(
 | 
	
		
			
				|  |  | +                VERTEX_CLASSIII[v][0] + this.coord.i,
 | 
	
		
			
				|  |  | +                VERTEX_CLASSIII[v][1] + this.coord.j,
 | 
	
		
			
				|  |  | +                VERTEX_CLASSIII[v][2] + this.coord.k
 | 
	
		
			
				|  |  | +            );
 | 
	
		
			
				|  |  | +            fijk.coord.ijkNormalize();
 | 
	
		
			
				|  |  |              fijk.face = this.face;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              final Overage overage = fijk.adjustOverageClassII(adjRes, false, true);
 | 
	
	
		
			
				|  | @@ -572,50 +604,20 @@ final class FaceIJK {
 | 
	
		
			
				|  |  |              projection. Note that Class II cell edges have vertices on the face
 | 
	
		
			
				|  |  |              edge, with no edge line intersections.
 | 
	
		
			
				|  |  |              */
 | 
	
		
			
				|  |  | -            if (isResolutionClassIII && vert > start && fijk.face != lastFace && lastOverage != Overage.FACE_EDGE) {
 | 
	
		
			
				|  |  | +            if (vert > 0 && fijk.face != lastFace && lastOverage != Overage.FACE_EDGE) {
 | 
	
		
			
				|  |  |                  // find hex2d of the two vertexes on original face
 | 
	
		
			
				|  |  |                  final int lastV = (v + 5) % Constants.NUM_HEX_VERTS;
 | 
	
		
			
				|  |  |                  // 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.
 | 
	
		
			
				|  |  | -                final int[] vertexLast = verts[lastV];
 | 
	
		
			
				|  |  | -                final int[] vertexV = verts[v];
 | 
	
		
			
				|  |  | -                scratch2.reset(vertexLast[0] + this.coord.i, vertexLast[1] + this.coord.j, vertexLast[2] + this.coord.k);
 | 
	
		
			
				|  |  | -                scratch2.ijkNormalize();
 | 
	
		
			
				|  |  | -                final Vec2d orig2d0 = scratch2.ijkToHex2d();
 | 
	
		
			
				|  |  | -                scratch2.reset(vertexV[0] + this.coord.i, vertexV[1] + this.coord.j, vertexV[2] + this.coord.k);
 | 
	
		
			
				|  |  | -                scratch2.ijkNormalize();
 | 
	
		
			
				|  |  | -                final Vec2d orig2d1 = scratch2.ijkToHex2d();
 | 
	
		
			
				|  |  | +                final Vec2d orig2d0 = orig(scratch, VERTEX_CLASSIII[lastV]);
 | 
	
		
			
				|  |  | +                final Vec2d orig2d1 = orig(scratch, VERTEX_CLASSIII[v]);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                  // find the appropriate icosa face edge vertexes
 | 
	
		
			
				|  |  |                  final int face2 = ((lastFace == this.face) ? fijk.face : lastFace);
 | 
	
		
			
				|  |  | -                final Vec2d edge0;
 | 
	
		
			
				|  |  | -                final Vec2d edge1;
 | 
	
		
			
				|  |  | -                switch (adjacentFaceDir[this.face][face2]) {
 | 
	
		
			
				|  |  | -                    case IJ -> {
 | 
	
		
			
				|  |  | -                        edge0 = maxDimByCIIVec2d[adjRes][0];
 | 
	
		
			
				|  |  | -                        edge1 = maxDimByCIIVec2d[adjRes][1];
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | -                    case JK -> {
 | 
	
		
			
				|  |  | -                        edge0 = maxDimByCIIVec2d[adjRes][1];
 | 
	
		
			
				|  |  | -                        edge1 = maxDimByCIIVec2d[adjRes][2];
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | -                    // case KI:
 | 
	
		
			
				|  |  | -                    default -> {
 | 
	
		
			
				|  |  | -                        assert (adjacentFaceDir[this.face][face2] == KI);
 | 
	
		
			
				|  |  | -                        edge0 = maxDimByCIIVec2d[adjRes][2];
 | 
	
		
			
				|  |  | -                        edge1 = maxDimByCIIVec2d[adjRes][0];
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  |                  // find the intersection and add the lat/lng point to the result
 | 
	
		
			
				|  |  | -                final Vec2d inter = Vec2d.v2dIntersect(orig2d0, orig2d1, edge0, edge1);
 | 
	
		
			
				|  |  | -                /*
 | 
	
		
			
				|  |  | -                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.
 | 
	
		
			
				|  |  | -                */
 | 
	
		
			
				|  |  | -                final boolean isIntersectionAtVertex = orig2d0.numericallyIdentical(inter) || orig2d1.numericallyIdentical(inter);
 | 
	
		
			
				|  |  | -                if (isIntersectionAtVertex == false) {
 | 
	
		
			
				|  |  | +                final Vec2d inter = findIntersectionPoint(orig2d0, orig2d1, adjRes, adjacentFaceDir[this.face][face2]);
 | 
	
		
			
				|  |  | +                if (inter != null) {
 | 
	
		
			
				|  |  |                      points[numPoints++] = inter.hex2dToGeo(this.face, adjRes, true);
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |              }
 | 
	
	
		
			
				|  | @@ -623,7 +625,7 @@ final class FaceIJK {
 | 
	
		
			
				|  |  |              // convert vertex to lat/lng and add to the result
 | 
	
		
			
				|  |  |              // vert == start + NUM_HEX_VERTS is only used to test for possible
 | 
	
		
			
				|  |  |              // intersection on last edge
 | 
	
		
			
				|  |  | -            if (vert < start + Constants.NUM_HEX_VERTS) {
 | 
	
		
			
				|  |  | +            if (vert < Constants.NUM_HEX_VERTS) {
 | 
	
		
			
				|  |  |                  points[numPoints++] = fijk.coord.ijkToGeo(fijk.face, adjRes, true);
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |              lastFace = fijk.face;
 | 
	
	
		
			
				|  | @@ -632,6 +634,42 @@ final class FaceIJK {
 | 
	
		
			
				|  |  |          return new CellBoundary(points, numPoints);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    private Vec2d orig(CoordIJK scratch, int[] vertexLast) {
 | 
	
		
			
				|  |  | +        scratch.reset(vertexLast[0] + this.coord.i, vertexLast[1] + this.coord.j, vertexLast[2] + this.coord.k);
 | 
	
		
			
				|  |  | +        scratch.ijkNormalize();
 | 
	
		
			
				|  |  | +        return scratch.ijkToHex2d();
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    private Vec2d findIntersectionPoint(Vec2d orig2d0, Vec2d orig2d1, int adjRes, int faceDir) {
 | 
	
		
			
				|  |  | +        // find the appropriate icosa face edge vertexes
 | 
	
		
			
				|  |  | +        final Vec2d edge0;
 | 
	
		
			
				|  |  | +        final Vec2d edge1;
 | 
	
		
			
				|  |  | +        switch (faceDir) {
 | 
	
		
			
				|  |  | +            case IJ -> {
 | 
	
		
			
				|  |  | +                edge0 = maxDimByCIIVec2d[adjRes][0];
 | 
	
		
			
				|  |  | +                edge1 = maxDimByCIIVec2d[adjRes][1];
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            case JK -> {
 | 
	
		
			
				|  |  | +                edge0 = maxDimByCIIVec2d[adjRes][1];
 | 
	
		
			
				|  |  | +                edge1 = maxDimByCIIVec2d[adjRes][2];
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            // case KI:
 | 
	
		
			
				|  |  | +            default -> {
 | 
	
		
			
				|  |  | +                assert (faceDir == KI);
 | 
	
		
			
				|  |  | +                edge0 = maxDimByCIIVec2d[adjRes][2];
 | 
	
		
			
				|  |  | +                edge1 = maxDimByCIIVec2d[adjRes][0];
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        // find the intersection and add the lat/lng point to the result
 | 
	
		
			
				|  |  | +        final Vec2d inter = Vec2d.v2dIntersect(orig2d0, orig2d1, edge0, edge1);
 | 
	
		
			
				|  |  | +        /*
 | 
	
		
			
				|  |  | +        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.
 | 
	
		
			
				|  |  | +        */
 | 
	
		
			
				|  |  | +        return orig2d0.numericallyIdentical(inter) || orig2d1.numericallyIdentical(inter) ? null : inter;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      /**
 | 
	
		
			
				|  |  |       * compute the corresponding H3Index.
 | 
	
		
			
				|  |  |       * @param res The cell resolution.
 | 
	
	
		
			
				|  | @@ -651,7 +689,6 @@ final class FaceIJK {
 | 
	
		
			
				|  |  |                  // out of range input
 | 
	
		
			
				|  |  |                  throw new IllegalArgumentException(" out of range input");
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |              return H3Index.H3_set_base_cell(h, BaseCells.getBaseCell(face, coord));
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 |