Ver Fonte

Add methods that return polar cells in H3 library (#92780)

Ignacio Vera há 2 anos atrás
pai
commit
9b3f8db438

+ 55 - 0
libs/h3/src/main/java/org/elasticsearch/h3/H3.java

@@ -33,6 +33,15 @@ public final class H3 {
 
     public static int MAX_H3_RES = Constants.MAX_H3_RES;
 
+    private static final long[] NORTH = new long[MAX_H3_RES + 1];
+    private static final long[] SOUTH = new long[MAX_H3_RES + 1];
+    static {
+        for (int res = 0; res <= H3.MAX_H3_RES; res++) {
+            NORTH[res] = H3.geoToH3(90, 0, res);
+            SOUTH[res] = H3.geoToH3(-90, 0, res);
+        }
+    }
+
     /**
      * Converts from <code>long</code> representation of an index to <code>String</code> representation.
      */
@@ -517,6 +526,52 @@ public final class H3 {
         return h3ToNotIntersectingChildrenSize(stringToH3(h3Address));
     }
 
+    /**
+     * Find the h3 index containing the North Pole at the given resolution.
+     *
+     * @param res the provided resolution.
+     *
+     * @return the h3 index containing the North Pole.
+     */
+    public static long northPolarH3(int res) {
+        checkResolution(res);
+        return NORTH[res];
+    }
+
+    /**
+     * Find the h3 address containing the North Pole at the given resolution.
+     *
+     * @param res the provided resolution.
+     *
+     * @return the h3 address containing the North Pole.
+     */
+    public static String northPolarH3Address(int res) {
+        return h3ToString(northPolarH3(res));
+    }
+
+    /**
+     * Find the h3 index containing the South Pole at the given resolution.
+     *
+     * @param res the provided resolution.
+     *
+     * @return the h3 index containing the South Pole.
+     */
+    public static long southPolarH3(int res) {
+        checkResolution(res);
+        return SOUTH[res];
+    }
+
+    /**
+     * Find the h3 address containing the South Pole at the given resolution.
+     *
+     * @param res the provided resolution.
+     *
+     * @return the h3 address containing the South Pole.
+     */
+    public static String southPolarH3Address(int res) {
+        return h3ToString(southPolarH3(res));
+    }
+
     /**
      * _ipow does integer exponentiation efficiently. Taken from StackOverflow.
      *

+ 12 - 0
libs/h3/src/test/java/org/elasticsearch/h3/GeoToH3Tests.java

@@ -55,4 +55,16 @@ public class GeoToH3Tests extends ESTestCase {
         }
         return GeoPolygonFactory.makeGeoPolygon(PlanetModel.SPHERE, points);
     }
+
+    public void testNorthPoleCells() {
+        for (int res = 0; res <= H3.MAX_H3_RES; res++) {
+            assertEquals(H3.northPolarH3Address(res), H3.geoToH3Address(90, GeoTestUtil.nextLongitude(), res));
+        }
+    }
+
+    public void testSouthPoleCells() {
+        for (int res = 0; res <= H3.MAX_H3_RES; res++) {
+            assertEquals(H3.southPolarH3Address(res), H3.geoToH3Address(-90, GeoTestUtil.nextLongitude(), res));
+        }
+    }
 }

+ 15 - 22
x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/common/H3CartesianUtil.java

@@ -33,14 +33,7 @@ public final class H3CartesianUtil {
     public static final int MAX_ARRAY_SIZE = 15;
     private static final DoubleUnaryOperator NORMALIZE_LONG_POS = lon -> lon < 0 ? lon + 360d : lon;
     private static final DoubleUnaryOperator NORMALIZE_LONG_NEG = lon -> lon > 0 ? lon - 360d : lon;
-    private static final long[] NORTH = new long[16];
-    private static final long[] SOUTH = new long[16];
-    static {
-        for (int res = 0; res <= H3.MAX_H3_RES; res++) {
-            NORTH[res] = H3.geoToH3(90, 0, res);
-            SOUTH[res] = H3.geoToH3(-90, 0, res);
-        }
-    }
+
     // we cache the first two levels and polar polygons
     private static final Map<Long, double[][]> CACHED_H3 = new HashMap<>();
     static {
@@ -51,24 +44,24 @@ public final class H3CartesianUtil {
             }
         }
         for (int res = 2; res <= H3.MAX_H3_RES; res++) {
-            CACHED_H3.put(NORTH[res], getCoordinates(NORTH[res]));
-            CACHED_H3.put(SOUTH[res], getCoordinates(SOUTH[res]));
+            CACHED_H3.put(H3.northPolarH3(res), getCoordinates(H3.northPolarH3(res)));
+            CACHED_H3.put(H3.southPolarH3(res), getCoordinates(H3.southPolarH3(res)));
         }
     }
 
-    private static final double[] NORTH_BOUND = new double[16];
-    private static final double[] SOUTH_BOUND = new double[16];
+    private static final double[] NORTH_BOUND = new double[H3.MAX_H3_RES + 1];
+    private static final double[] SOUTH_BOUND = new double[H3.MAX_H3_RES + 1];
     static {
         for (int res = 0; res <= H3.MAX_H3_RES; res++) {
-            NORTH_BOUND[res] = toBoundingBox(NORTH[res]).getMinY();
-            SOUTH_BOUND[res] = toBoundingBox(SOUTH[res]).getMaxY();
+            NORTH_BOUND[res] = toBoundingBox(H3.northPolarH3(res)).getMinY();
+            SOUTH_BOUND[res] = toBoundingBox(H3.southPolarH3(res)).getMaxY();
         }
     }
 
-    /** For the given resolution, it returns the maximum latitude of the h3 bin containing the south pole */
+    /** For the given resolution, it returns true if the cell contains any of the poles */
     public static boolean isPolar(long h3) {
-        final int resolution = H3.getResolution(h3);
-        return SOUTH[resolution] == h3 || NORTH[resolution] == h3;
+        final int res = H3.getResolution(h3);
+        return H3.southPolarH3(res) == h3 || H3.northPolarH3(res) == h3;
     }
 
     /** For the given resolution, it returns the maximum latitude of the h3 bin containing the south pole */
@@ -97,9 +90,9 @@ public final class H3CartesianUtil {
             System.arraycopy(cached[1], 0, ys, 0, cached[0].length);
             return cached[0].length;
         }
-        final int resolution = H3.getResolution(h3);
-        final double pole = NORTH[resolution] == h3 ? GeoEncodingUtils.decodeLatitude(GeoEncodingUtils.encodeLatitude(90d))
-            : SOUTH[resolution] == h3 ? GeoEncodingUtils.decodeLatitude(GeoEncodingUtils.encodeLatitude(-90d))
+        final int res = H3.getResolution(h3);
+        final double pole = H3.northPolarH3(res) == h3 ? GeoEncodingUtils.decodeLatitude(GeoEncodingUtils.encodeLatitude(90d))
+            : H3.southPolarH3(res) == h3 ? GeoEncodingUtils.decodeLatitude(GeoEncodingUtils.encodeLatitude(-90d))
             : Double.NaN;
         final CellBoundary cellBoundary = H3.h3ToGeoBoundary(h3);
         final int numPoints;
@@ -200,9 +193,9 @@ public final class H3CartesianUtil {
             }
         }
         final int res = H3.getResolution(h3);
-        if (h3 == NORTH[res]) {
+        if (h3 == H3.northPolarH3(res)) {
             return new org.elasticsearch.geometry.Rectangle(-180d, 180d, 90d, minLat);
-        } else if (h3 == SOUTH[res]) {
+        } else if (h3 == H3.southPolarH3(res)) {
             return new org.elasticsearch.geometry.Rectangle(-180d, 180d, maxLat, -90d);
         } else if (maxLon - minLon > 180d) {
             return new org.elasticsearch.geometry.Rectangle(minPosLon, maxNegLon, maxLat, minLat);

+ 2 - 2
x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/search/aggregations/bucket/geogrid/GeoHexCellIdSource.java

@@ -118,8 +118,8 @@ public class GeoHexCellIdSource extends CellIdSource {
         GeoHexPredicate(GeoBoundingBox bbox, int precision) {
             this.crossesDateline = bbox.right() < bbox.left();
             this.bbox = bbox;
-            northPoleHex = H3.geoToH3(90, 0, precision);
-            southPoleHex = H3.geoToH3(-90, 0, precision);
+            northPoleHex = H3.northPolarH3(precision);
+            southPoleHex = H3.southPolarH3(precision);
         }
 
         public boolean validHex(long hex) {