浏览代码

Reduce number of object allocations in H3#h3ToGeoBoundary (#91586)

Ignacio Vera 2 年之前
父节点
当前提交
ff9af20b0f

+ 5 - 0
docs/changelog/91586.yaml

@@ -0,0 +1,5 @@
+pr: 91586
+summary: Reduce number of object allocations in H3#h3ToGeoBoundary
+area: Geo
+type: enhancement
+issues: []

+ 153 - 213
libs/h3/src/main/java/org/elasticsearch/h3/FaceIJK.java

@@ -84,6 +84,15 @@ final class FaceIJK {
         11529602  // res 16
         11529602  // res 16
     };
     };
 
 
+    private static final Vec2d[][] maxDimByCIIVec2d = new Vec2d[maxDimByCIIres.length][3];
+    static {
+        for (int i = 0; i < maxDimByCIIres.length; i++) {
+            maxDimByCIIVec2d[i][0] = new Vec2d(3.0 * maxDimByCIIres[i], 0.0);
+            maxDimByCIIVec2d[i][1] = new Vec2d(-1.5 * maxDimByCIIres[i], 3.0 * Constants.M_SQRT3_2 * maxDimByCIIres[i]);
+            maxDimByCIIVec2d[i][2] = new Vec2d(-1.5 * maxDimByCIIres[i], -3.0 * Constants.M_SQRT3_2 * maxDimByCIIres[i]);
+        }
+    }
+
     /**
     /**
      * unit scale distance table
      * unit scale distance table
      */
      */
@@ -305,6 +314,32 @@ final class FaceIJK {
             new FaceOrientIJK(14, 0, 2, 2, 3)   // jk quadrant
             new FaceOrientIJK(14, 0, 2, 2, 3)   // jk quadrant
         } };
         } };
 
 
+    // the vertexes of an origin-centered cell 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
+    private static final int[][] VERTEX_CLASSIII = new int[][] {
+        { 5, 4, 0 },  // 0
+        { 1, 5, 0 },  // 1
+        { 0, 5, 4 },  // 2
+        { 0, 1, 5 },  // 3
+        { 4, 0, 5 },  // 4
+        { 5, 0, 1 }   // 5
+    };
+
+    // the vertexes of an origin-centered cell 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
+    private static final int[][] VERTEX_CLASSII = new int[][] {
+        { 2, 1, 0 },  // 0
+        { 1, 2, 0 },  // 1
+        { 0, 2, 1 },  // 2
+        { 0, 1, 2 },  // 3
+        { 1, 0, 2 },  // 4
+        { 2, 0, 1 }   // 5
+    };
+
     int face;        // face number
     int face;        // face number
     CoordIJK coord;  // ijk coordinates on that face
     CoordIJK coord;  // ijk coordinates on that face
 
 
@@ -399,80 +434,87 @@ final class FaceIJK {
      * @param length The number of topological vertexes 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, int start, int length) {
-        FaceIJK[] fijkVerts = new FaceIJK[Constants.NUM_PENT_VERTS];
-        int adjRes = faceIjkPentToVerts(res, fijkVerts);
-
+        // 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;
+        }
         // If we're returning the entire loop, we need one more iteration in case
         // If we're returning the entire loop, we need one more iteration in case
         // of a distortion vertex on the last edge
         // of a distortion vertex on the last edge
-        int additionalIteration = length == Constants.NUM_PENT_VERTS ? 1 : 0;
-
+        final int additionalIteration = length == Constants.NUM_PENT_VERTS ? 1 : 0;
+        final boolean isResolutionClassIII = H3Index.isResolutionClassIII(res);
         // convert each vertex to lat/lng
         // convert each vertex to lat/lng
         // adjust the face of each vertex as appropriate and introduce
         // adjust the face of each vertex as appropriate and introduce
         // edge-crossing vertices as needed
         // edge-crossing vertices as needed
-        CellBoundary boundary = new CellBoundary();
-        FaceIJK lastFijk = null;
+        final CellBoundary boundary = new CellBoundary();
+        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 CoordIJK lastCoord = new CoordIJK(0, 0, 0);
+        int lastFace = this.face;
         for (int vert = start; vert < start + length + additionalIteration; vert++) {
         for (int vert = start; vert < start + length + additionalIteration; vert++) {
-            int v = vert % Constants.NUM_PENT_VERTS;
-
-            FaceIJK fijk = fijkVerts[v];
+            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.face = this.face;
 
 
             fijk.adjustPentVertOverage(adjRes);
             fijk.adjustPentVertOverage(adjRes);
 
 
             // all Class III pentagon edges cross icosa edges
             // all Class III pentagon edges cross icosa edges
             // note that Class II pentagons have vertices on the edge,
             // note that Class II pentagons have vertices on the edge,
             // not edge intersections
             // not edge intersections
-            if (H3Index.isResolutionClassIII(res) && vert > start) {
+            if (isResolutionClassIII && vert > start) {
                 // find hex2d of the two vertexes on the last face
                 // 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 = lastFijk.coord.ijkToHex2d();
-
-                int currentToLastDir = adjacentFaceDir[tmpFijk.face][lastFijk.face];
-
-                FaceOrientIJK fijkOrient = faceNeighbors[tmpFijk.face][currentToLastDir];
+                final Vec2d orig2d0 = lastCoord.ijkToHex2d();
 
 
-                tmpFijk.face = fijkOrient.face;
-                CoordIJK ijk = tmpFijk.coord;
+                final int currentToLastDir = adjacentFaceDir[fijk.face][lastFace];
+                final FaceOrientIJK fijkOrient = faceNeighbors[fijk.face][currentToLastDir];
 
 
+                lastCoord.reset(fijk.coord.i, fijk.coord.j, fijk.coord.k);
                 // rotate and translate for adjacent face
                 // rotate and translate for adjacent face
                 for (int i = 0; i < fijkOrient.ccwRot60; i++) {
                 for (int i = 0; i < fijkOrient.ccwRot60; i++) {
-                    ijk.ijkRotate60ccw();
+                    lastCoord.ijkRotate60ccw();
                 }
                 }
 
 
-                int unitScale = unitScaleByCIIres[adjRes] * 3;
-                ijk.ijkAdd(fijkOrient.translateI * unitScale, fijkOrient.translateJ * unitScale, fijkOrient.translateK * unitScale);
-                ijk.ijkNormalize();
+                final int unitScale = unitScaleByCIIres[adjRes] * 3;
+                lastCoord.ijkAdd(fijkOrient.translateI * unitScale, fijkOrient.translateJ * unitScale, fijkOrient.translateK * unitScale);
+                lastCoord.ijkNormalize();
 
 
-                Vec2d orig2d1 = ijk.ijkToHex2d();
+                final Vec2d orig2d1 = lastCoord.ijkToHex2d();
 
 
                 // find the appropriate icosa face edge vertexes
                 // 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;
-                Vec2d edge1;
-                switch (adjacentFaceDir[tmpFijk.face][fijk.face]) {
-                    case IJ:
-                        edge0 = v0;
-                        edge1 = v1;
-                        break;
-                    case JK:
-                        edge0 = v1;
-                        edge1 = v2;
-                        break;
-                    case KI:
-                    default:
-                        assert (adjacentFaceDir[tmpFijk.face][fijk.face] == KI);
-                        edge0 = v2;
-                        edge1 = v0;
-                        break;
+                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
                 // find the intersection and add the lat/lng point to the result
-                Vec2d inter = Vec2d.v2dIntersect(orig2d0, orig2d1, edge0, edge1);
-                LatLng point = inter.hex2dToGeo(tmpFijk.face, adjRes, true);
+                final Vec2d inter = Vec2d.v2dIntersect(orig2d0, orig2d1, edge0, edge1);
+                final LatLng point = inter.hex2dToGeo(fijkOrient.face, adjRes, true);
                 boundary.add(point);
                 boundary.add(point);
             }
             }
 
 
@@ -480,12 +522,12 @@ final class FaceIJK {
             // vert == start + NUM_PENT_VERTS is only used to test for possible
             // vert == start + NUM_PENT_VERTS is only used to test for possible
             // intersection on last edge
             // intersection on last edge
             if (vert < start + Constants.NUM_PENT_VERTS) {
             if (vert < start + Constants.NUM_PENT_VERTS) {
-                Vec2d vec = fijk.coord.ijkToHex2d();
-                LatLng point = vec.hex2dToGeo(fijk.face, adjRes, true);
+                final Vec2d vec = fijk.coord.ijkToHex2d();
+                final LatLng point = vec.hex2dToGeo(fijk.face, adjRes, true);
                 boundary.add(point);
                 boundary.add(point);
             }
             }
-
-            lastFijk = fijk;
+            lastFace = fijk.face;
+            lastCoord.reset(fijk.coord.i, fijk.coord.j, fijk.coord.k);
         }
         }
         return boundary;
         return boundary;
     }
     }
@@ -498,27 +540,42 @@ final class FaceIJK {
      * @param start  The first topological vertex to return.
      * @param start  The first topological vertex to return.
      * @param length The number of topological vertexes to return.
      * @param length The number of topological vertexes to return.
      */
      */
-    public CellBoundary faceIjkToCellBoundary(int res, int start, int length) {
-        FaceIJK fijkVerts[] = new FaceIJK[Constants.NUM_HEX_VERTS];
-        int adjRes = faceIjkToVerts(res, fijkVerts);
+    public CellBoundary faceIjkToCellBoundary(final int res, final int start, final int length) {
+        // 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;
+        }
+
         // If we're returning the entire loop, we need one more iteration in case
         // If we're returning the entire loop, we need one more iteration in case
         // of a distortion vertex on the last edge
         // of a distortion vertex on the last edge
-        int additionalIteration = length == Constants.NUM_HEX_VERTS ? 1 : 0;
-
+        final int additionalIteration = length == Constants.NUM_HEX_VERTS ? 1 : 0;
+        final boolean isResolutionClassIII = H3Index.isResolutionClassIII(res);
         // convert each vertex to lat/lng
         // convert each vertex to lat/lng
         // adjust the face of each vertex as appropriate and introduce
         // adjust the face of each vertex as appropriate and introduce
         // edge-crossing vertices as needed
         // edge-crossing vertices as needed
-        CellBoundary boundary = new CellBoundary();
+        final CellBoundary boundary = new CellBoundary();
+        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;
         int lastFace = -1;
         int lastFace = -1;
         Overage lastOverage = Overage.NO_OVERAGE;
         Overage lastOverage = Overage.NO_OVERAGE;
         for (int vert = start; vert < start + length + additionalIteration; vert++) {
         for (int vert = start; vert < start + length + additionalIteration; vert++) {
             int v = vert % Constants.NUM_HEX_VERTS;
             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();
+            fijk.face = this.face;
 
 
-            FaceIJK fijk = new FaceIJK(fijkVerts[v].face, new CoordIJK(fijkVerts[v].coord.i, fijkVerts[v].coord.j, fijkVerts[v].coord.k));
-
-            //
-            final boolean pentLeading4 = false; // may change in c code when calling method
-            Overage overage = fijk.adjustOverageClassII(adjRes, pentLeading4, true);
+            final Overage overage = fijk.adjustOverageClassII(adjRes, false, true);
 
 
             /*
             /*
             Check for edge-crossing. Each face of the underlying icosahedron is a
             Check for edge-crossing. Each face of the underlying icosahedron is a
@@ -529,48 +586,51 @@ final class FaceIJK {
             projection. Note that Class II cell edges have vertices on the face
             projection. Note that Class II cell edges have vertices on the face
             edge, with no edge line intersections.
             edge, with no edge line intersections.
             */
             */
-            if (H3Index.isResolutionClassIII(res) && vert > start && fijk.face != lastFace && lastOverage != Overage.FACE_EDGE) {
+            if (isResolutionClassIII && vert > start && fijk.face != lastFace && lastOverage != Overage.FACE_EDGE) {
                 // find hex2d of the two vertexes on original face
                 // find hex2d of the two vertexes on original face
-                int lastV = (v + 5) % Constants.NUM_HEX_VERTS;
-                Vec2d orig2d0 = fijkVerts[lastV].coord.ijkToHex2d();
-                Vec2d orig2d1 = fijkVerts[v].coord.ijkToHex2d();
+                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] + coord.i, vertexLast[1] + coord.j, vertexLast[2] + coord.k);
+                scratch2.ijkNormalize();
+                final Vec2d orig2d0 = scratch2.ijkToHex2d();
+                scratch2.reset(vertexV[0] + coord.i, vertexV[1] + coord.j, vertexV[2] + coord.k);
+                scratch2.ijkNormalize();
+                final Vec2d orig2d1 = scratch2.ijkToHex2d();
 
 
                 // find the appropriate icosa face edge vertexes
                 // 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);
-
-                int face2 = ((lastFace == this.face) ? fijk.face : lastFace);
+                final int face2 = ((lastFace == this.face) ? fijk.face : lastFace);
                 final Vec2d edge0;
                 final Vec2d edge0;
                 final Vec2d edge1;
                 final Vec2d edge1;
                 switch (adjacentFaceDir[this.face][face2]) {
                 switch (adjacentFaceDir[this.face][face2]) {
-                    case IJ:
-                        edge0 = v0;
-                        edge1 = v1;
-                        break;
-                    case JK:
-                        edge0 = v1;
-                        edge1 = v2;
-                        break;
+                    case IJ -> {
+                        edge0 = maxDimByCIIVec2d[adjRes][0];
+                        edge1 = maxDimByCIIVec2d[adjRes][1];
+                    }
+                    case JK -> {
+                        edge0 = maxDimByCIIVec2d[adjRes][1];
+                        edge1 = maxDimByCIIVec2d[adjRes][2];
+                    }
                     // case KI:
                     // case KI:
-                    default:
+                    default -> {
                         assert (adjacentFaceDir[this.face][face2] == KI);
                         assert (adjacentFaceDir[this.face][face2] == KI);
-                        edge0 = v2;
-                        edge1 = v0;
-                        break;
+                        edge0 = maxDimByCIIVec2d[adjRes][2];
+                        edge1 = maxDimByCIIVec2d[adjRes][0];
+                    }
                 }
                 }
-
                 // find the intersection and add the lat/lng point to the result
                 // find the intersection and add the lat/lng point to the result
-                Vec2d inter = Vec2d.v2dIntersect(orig2d0, orig2d1, edge0, edge1);
+                final Vec2d inter = Vec2d.v2dIntersect(orig2d0, orig2d1, edge0, edge1);
                 /*
                 /*
                 If a point of intersection occurs at a hexagon vertex, then each
                 If a point of intersection occurs at a hexagon vertex, then each
                 adjacent hexagon edge will lie completely on a single icosahedron
                 adjacent hexagon edge will lie completely on a single icosahedron
                 face, and no additional vertex is required.
                 face, and no additional vertex is required.
                 */
                 */
-                boolean isIntersectionAtVertex = orig2d0.equals(inter) || orig2d1.equals(inter);
+                final boolean isIntersectionAtVertex = orig2d0.equals(inter) || orig2d1.equals(inter);
                 if (isIntersectionAtVertex == false) {
                 if (isIntersectionAtVertex == false) {
-                    LatLng point = inter.hex2dToGeo(this.face, adjRes, true);
+                    final LatLng point = inter.hex2dToGeo(this.face, adjRes, true);
                     boundary.add(point);
                     boundary.add(point);
                 }
                 }
             }
             }
@@ -579,8 +639,8 @@ final class FaceIJK {
             // vert == start + NUM_HEX_VERTS is only used to test for possible
             // vert == start + NUM_HEX_VERTS is only used to test for possible
             // intersection on last edge
             // intersection on last edge
             if (vert < start + Constants.NUM_HEX_VERTS) {
             if (vert < start + Constants.NUM_HEX_VERTS) {
-                Vec2d vec = fijk.coord.ijkToHex2d();
-                LatLng point = vec.hex2dToGeo(fijk.face, adjRes, true);
+                final Vec2d vec = fijk.coord.ijkToHex2d();
+                final LatLng point = vec.hex2dToGeo(fijk.face, adjRes, true);
                 boundary.add(point);
                 boundary.add(point);
             }
             }
             lastFace = fijk.face;
             lastFace = fijk.face;
@@ -677,125 +737,6 @@ final class FaceIJK {
         return h;
         return h;
     }
     }
 
 
-    /**
-     * Populate the vertices of this cell as substrate FaceIJK addresses.
-     *
-     * @param res The H3 resolution of the cell. This may be adjusted if
-     *            necessary for the substrate grid resolution.
-     */
-    private int faceIjkToVerts(int res, FaceIJK[] fijkVerts) {
-        // get the correct set of substrate vertices for this resolution
-        CoordIJK[] verts;
-        if (H3Index.isResolutionClassIII(res)) {
-            // the vertexes of an origin-centered cell 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
-            verts = new CoordIJK[] {
-                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
-                new CoordIJK(5, 0, 1)   // 5
-            };
-        } else {
-            // the vertexes of an origin-centered cell 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
-            verts = new CoordIJK[] {
-                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
-                new CoordIJK(2, 0, 1)   // 5
-            };
-        }
-
-        // 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
-        if (H3Index.isResolutionClassIII(res)) {
-            this.coord.downAp7r();
-            res += 1;
-        }
-
-        // 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.
-
-        for (int v = 0; v < Constants.NUM_HEX_VERTS; v++) {
-            verts[v].ijkAdd(this.coord.i, this.coord.j, this.coord.k);
-            verts[v].ijkNormalize();
-            fijkVerts[v] = new FaceIJK(this.face, verts[v]);
-        }
-        return res;
-    }
-
-    /**
-     * Populate the vertices of this pentagon cell as substrate FaceIJK addresses
-     *
-     * @param res The H3 resolution of the cell. This may be adjusted if
-     *            necessary for the substrate grid resolution.
-     */
-    private int faceIjkPentToVerts(int res, FaceIJK[] fijkVerts) {
-        // get the correct set of substrate vertices for this resolution
-        CoordIJK[] verts;
-        if (H3Index.isResolutionClassIII(res)) {
-            // 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
-            verts = new CoordIJK[] {
-                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
-            };
-        } else {
-            // 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
-            verts = new CoordIJK[] {
-                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
-            };
-        }
-
-        // 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
-        if (H3Index.isResolutionClassIII(res)) {
-            this.coord.downAp7r();
-            res += 1;
-        }
-
-        // 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.
-        for (int v = 0; v < Constants.NUM_PENT_VERTS; v++) {
-            verts[v].ijkAdd(this.coord.i, this.coord.j, this.coord.k);
-            verts[v].ijkNormalize();
-            fijkVerts[v] = new FaceIJK(this.face, verts[v]);
-        }
-        return res;
-    }
-
     /**
     /**
      * Adjusts a FaceIJK address for a pentagon vertex in a substrate grid in
      * Adjusts a FaceIJK address for a pentagon vertex in a substrate grid in
      * place so that the resulting cell address is relative to the correct
      * place so that the resulting cell address is relative to the correct
@@ -803,11 +744,10 @@ final class FaceIJK {
      *
      *
      * @param res The H3 resolution of the cell.
      * @param res The H3 resolution of the cell.
      */
      */
-    private Overage adjustPentVertOverage(int res) {
+    private void adjustPentVertOverage(int res) {
         Overage overage;
         Overage overage;
         do {
         do {
             overage = adjustOverageClassII(res, false, true);
             overage = adjustOverageClassII(res, false, true);
         } while (overage == Overage.NEW_FACE);
         } while (overage == Overage.NEW_FACE);
-        return overage;
     }
     }
 }
 }

+ 4 - 3
libs/h3/src/main/java/org/elasticsearch/h3/H3Index.java

@@ -206,8 +206,9 @@ final class H3Index {
         }
         }
         // if we're here we have the potential for an "overage"; i.e., it is
         // if we're here we have the potential for an "overage"; i.e., it is
         // possible that c lies on an adjacent face
         // possible that c lies on an adjacent face
-
-        CoordIJK origIJK = new CoordIJK(fijk.coord.i, fijk.coord.j, fijk.coord.k);
+        int origI = fijk.coord.i;
+        int origJ = fijk.coord.j;
+        int origK = fijk.coord.k;
 
 
         // if we're in Class III, drop into the next finer Class II grid
         // if we're in Class III, drop into the next finer Class II grid
         int res = H3Index.H3_get_resolution(h3);
         int res = H3Index.H3_get_resolution(h3);
@@ -234,7 +235,7 @@ final class H3Index {
                 fijk.coord.upAp7r();
                 fijk.coord.upAp7r();
             }
             }
         } else if (res != H3Index.H3_get_resolution(h3)) {
         } else if (res != H3Index.H3_get_resolution(h3)) {
-            fijk.coord = origIJK;
+            fijk.coord.reset(origI, origJ, origK);
         }
         }
         return fijk;
         return fijk;
     }
     }

+ 11 - 5
libs/h3/src/main/java/org/elasticsearch/h3/Vec2d.java

@@ -146,11 +146,12 @@ final class Vec2d {
 
 
         // adjust theta for Class III
         // adjust theta for Class III
         // if a substrate grid, then it's already been adjusted for Class III
         // if a substrate grid, then it's already been adjusted for Class III
-        if (substrate == false && H3Index.isResolutionClassIII(res)) theta = posAngleRads(theta + Constants.M_AP7_ROT_RADS);
+        if (substrate == false && H3Index.isResolutionClassIII(res)) {
+            theta = posAngleRads(theta + Constants.M_AP7_ROT_RADS);
+        }
 
 
         // find theta as an azimuth
         // find theta as an azimuth
         theta = posAngleRads(faceAxesAzRadsCII[face][0] - theta);
         theta = posAngleRads(faceAxesAzRadsCII[face][0] - theta);
-
         // now find the point at (r,theta) from the face center
         // now find the point at (r,theta) from the face center
         return geoAzDistanceRads(faceCenterGeo[face], theta, r);
         return geoAzDistanceRads(faceCenterGeo[face], theta, r);
     }
     }
@@ -353,7 +354,11 @@ final class Vec2d {
                 lon = constrainLng(p1.getLonRad());
                 lon = constrainLng(p1.getLonRad());
             }
             }
         } else { // not due north or south
         } else { // not due north or south
-            sinlat = Math.sin(p1.getLatRad()) * Math.cos(distance) + Math.cos(p1.getLatRad()) * Math.sin(distance) * Math.cos(az);
+            final double sinDistance = Math.sin(distance);
+            final double cosDistance = Math.cos(distance);
+            final double sinP1Lat = Math.sin(p1.getLatRad());
+            final double cosP1Lat = Math.cos(p1.getLatRad());
+            sinlat = sinP1Lat * cosDistance + cosP1Lat * sinDistance * Math.cos(az);
             if (sinlat > 1.0) {
             if (sinlat > 1.0) {
                 sinlat = 1.0;
                 sinlat = 1.0;
             }
             }
@@ -370,8 +375,9 @@ final class Vec2d {
                 lat = -M_PI_2;
                 lat = -M_PI_2;
                 lon = 0.0;
                 lon = 0.0;
             } else {
             } else {
-                sinlng = Math.sin(az) * Math.sin(distance) / Math.cos(lat);
-                coslng = (Math.cos(distance) - Math.sin(p1.getLatRad()) * Math.sin(lat)) / Math.cos(p1.getLatRad()) / Math.cos(lat);
+                final double cosLat = Math.cos(lat);
+                sinlng = Math.sin(az) * sinDistance / cosLat;
+                coslng = (cosDistance - sinP1Lat * Math.sin(lat)) / cosP1Lat / cosLat;
                 if (sinlng > 1.0) {
                 if (sinlng > 1.0) {
                     sinlng = 1.0;
                     sinlng = 1.0;
                 }
                 }