diff --git a/README.md b/README.md
index 9725965..801fdbd 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@
[](https://coveralls.io/github/uber/h3-java?branch=master)
[](LICENSE)
[](https://maven-badges.herokuapp.com/maven-central/com.uber/h3)
-[](https://github.com/uber/h3/releases/tag/v4.1.0)
+[](https://github.com/uber/h3/releases/tag/v4.2.0)
This library provides Java bindings for the [H3 Core Library](https://github.com/uber/h3). For API reference, please see the [H3 Documentation](https://h3geo.org/).
@@ -18,14 +18,14 @@ Add it to your pom.xml:
com.uber
h3
- 4.1.2
+ 4.2.0
```
Or, using Gradle:
```gradle
-compile("com.uber:h3:4.1.2")
+compile("com.uber:h3:4.2.0")
```
Encode a location into a hexagon address:
diff --git a/h3version.properties b/h3version.properties
index 3c21f6f..31fe3de 100644
--- a/h3version.properties
+++ b/h3version.properties
@@ -1 +1 @@
-h3.git.reference=v4.1.0
+h3.git.reference=v4.2.0
diff --git a/src/main/c/h3-java/build-h3-docker.sh b/src/main/c/h3-java/build-h3-docker.sh
index ea33597..08c0cb8 100755
--- a/src/main/c/h3-java/build-h3-docker.sh
+++ b/src/main/c/h3-java/build-h3-docker.sh
@@ -29,6 +29,7 @@ BUILD_ROOT=$1
UPGRADE_CMAKE=$2
CMAKE_ROOT=$3
+# TODO: This may no longer be necessary
if $UPGRADE_CMAKE; then
pushd "$CMAKE_ROOT"
if ! [ -e cmake-3.23.2-linux-x86_64.sh ]; then
@@ -51,6 +52,7 @@ mkdir -p build
pushd build
cmake -DBUILD_SHARED_LIBS=OFF \
+ -DENABLE_WARNINGS=OFF \
-DCMAKE_C_STANDARD_REQUIRED=ON \
-DCMAKE_C_STANDARD=99 \
-DCMAKE_POSITION_INDEPENDENT_CODE=ON \
diff --git a/src/main/c/h3-java/build-h3.sh b/src/main/c/h3-java/build-h3.sh
index a041ce8..cfa55ff 100755
--- a/src/main/c/h3-java/build-h3.sh
+++ b/src/main/c/h3-java/build-h3.sh
@@ -184,7 +184,7 @@ CMAKE_ROOT=target/cmake-3.23.2-linux-x86_64
mkdir -p $CMAKE_ROOT
DOCKCROSS_IMAGES="android-arm android-arm64 linux-arm64 linux-armv5 linux-armv7 linux-s390x linux-ppc64le linux-x64 linux-x86 windows-static-x64 windows-static-x86"
-if ! $DOCKCROSS_ONLY; then
+if ! [ -z $DOCKCROSS_ONLY ]; then
DOCKCROSS_IMAGES=$DOCKCROSS_ONLY
echo Building only: $DOCKCROSS_IMAGES
fi
diff --git a/src/main/c/h3-java/src/jniapi.c b/src/main/c/h3-java/src/jniapi.c
index 76c5762..61c4940 100644
--- a/src/main/c/h3-java/src/jniapi.c
+++ b/src/main/c/h3-java/src/jniapi.c
@@ -571,6 +571,32 @@ Java_com_uber_h3core_NativeMethods_maxPolygonToCellsSize(
return numHexagons;
}
+/*
+ * Class: com_uber_h3core_NativeMethods
+ * Method: maxPolygonToCellsSizeExperimental
+ * Signature: ([D[I[DII)J
+ */
+JNIEXPORT jlong JNICALL
+Java_com_uber_h3core_NativeMethods_maxPolygonToCellsSizeExperimental(
+ JNIEnv *env, jobject thiz, jdoubleArray verts, jintArray holeSizes,
+ jdoubleArray holeVerts, jint res, jint flags) {
+ GeoPolygon polygon;
+ if (CreateGeoPolygon(env, verts, holeSizes, holeVerts, &polygon)) {
+ return -1;
+ }
+
+ jlong numHexagons;
+ H3Error err =
+ maxPolygonToCellsSizeExperimental(&polygon, res, flags, &numHexagons);
+
+ DestroyGeoPolygon(env, verts, holeSizes, holeVerts, &polygon);
+
+ if (err) {
+ ThrowH3Exception(env, err);
+ }
+ return numHexagons;
+}
+
/*
* Class: com_uber_h3core_NativeMethods
* Method: getRes0Cells
@@ -657,6 +683,40 @@ JNIEXPORT void JNICALL Java_com_uber_h3core_NativeMethods_polygonToCells(
}
}
+/*
+ * Class: com_uber_h3core_NativeMethods
+ * Method: polygonToCellsExperimental
+ * Signature: ([D[I[DII[J)V
+ */
+JNIEXPORT void JNICALL
+Java_com_uber_h3core_NativeMethods_polygonToCellsExperimental(
+ JNIEnv *env, jobject thiz, jdoubleArray verts, jintArray holeSizes,
+ jdoubleArray holeVerts, jint res, jint flags, jlongArray results) {
+ GeoPolygon polygon;
+ if (CreateGeoPolygon(env, verts, holeSizes, holeVerts, &polygon)) {
+ return;
+ }
+
+ jlong *resultsElements = (**env).GetLongArrayElements(env, results, 0);
+ jsize resultsSize = (**env).GetArrayLength(env, results);
+
+ H3Error err;
+ if (resultsElements != NULL) {
+ err = polygonToCellsExperimental(&polygon, res, flags, resultsSize,
+ resultsElements);
+
+ (**env).ReleaseLongArrayElements(env, results, resultsElements, 0);
+ } else {
+ ThrowOutOfMemoryError(env);
+ }
+
+ DestroyGeoPolygon(env, verts, holeSizes, holeVerts, &polygon);
+
+ if (err) {
+ ThrowH3Exception(env, err);
+ }
+}
+
/**
* Converts the given polygon to managed objects
* (ArrayList>>)
@@ -1337,7 +1397,7 @@ JNIEXPORT jlong JNICALL Java_com_uber_h3core_NativeMethods_cellToVertex(
JNIEXPORT void JNICALL Java_com_uber_h3core_NativeMethods_cellToVertexes(
JNIEnv *env, jobject thiz, jlong h3, jlongArray vertexes) {
jsize sz = (**env).GetArrayLength(env, vertexes);
- jint *vertexesElements = (**env).GetLongArrayElements(env, vertexes, 0);
+ jlong *vertexesElements = (**env).GetLongArrayElements(env, vertexes, 0);
if (vertexesElements != NULL && sz >= 6) {
H3Error err = cellToVertexes(h3, vertexesElements);
diff --git a/src/main/java/com/uber/h3core/H3Core.java b/src/main/java/com/uber/h3core/H3Core.java
index d1b58de..3b24326 100644
--- a/src/main/java/com/uber/h3core/H3Core.java
+++ b/src/main/java/com/uber/h3core/H3Core.java
@@ -518,10 +518,68 @@ public List gridPathCells(long start, long end) {
}
/**
- * Finds indexes within the given geofence.
+ * Finds indexes within the given geopolygon.
*
- * @param points Outline geofence
- * @param holes Geofences of any internal holes
+ * @param points Outline geopolygon
+ * @param holes Geopolygons of any internal holes
+ * @param res Resolution of the desired indexes
+ */
+ public List polygonToCellAddressesExperimental(
+ List points, List> holes, PolygonToCellsFlags flags, int res) {
+ return h3ToStringList(polygonToCellsExperimental(points, holes, flags, res));
+ }
+
+ /**
+ * Finds indexes within the given geopolygon.
+ *
+ * @param points Outline geopolygon
+ * @param holes Geopolygon of any internal holes
+ * @param res Resolution of the desired indexes
+ * @throws IllegalArgumentException Invalid resolution
+ */
+ public List polygonToCellsExperimental(
+ List points, List> holes, PolygonToCellsFlags flags, int res) {
+ checkResolution(res);
+
+ // pack the data for use by the polyfill JNI call
+ double[] verts = new double[points.size() * 2];
+ packGeofenceVertices(verts, points, 0);
+ int[] holeSizes = new int[0];
+ double[] holeVerts = new double[0];
+ if (holes != null) {
+ int holesSize = holes.size();
+ holeSizes = new int[holesSize];
+ int totalSize = 0;
+ for (int i = 0; i < holesSize; i++) {
+ int holeSize = holes.get(i).size() * 2;
+ totalSize += holeSize;
+ // Note we are storing the number of doubles
+ holeSizes[i] = holeSize;
+ }
+ holeVerts = new double[totalSize];
+ int offset = 0;
+ for (int i = 0; i < holesSize; i++) {
+ offset = packGeofenceVertices(holeVerts, holes.get(i), offset);
+ }
+ }
+
+ int flagsInt = flags.toInt();
+ int sz =
+ longToIntSize(
+ h3Api.maxPolygonToCellsSizeExperimental(verts, holeSizes, holeVerts, res, flagsInt));
+
+ long[] results = new long[sz];
+
+ h3Api.polygonToCellsExperimental(verts, holeSizes, holeVerts, res, flagsInt, results);
+
+ return nonZeroLongArrayToList(results);
+ }
+
+ /**
+ * Finds indexes within the given geopolygon.
+ *
+ * @param points Outline geopolygon
+ * @param holes Geopolygons of any internal holes
* @param res Resolution of the desired indexes
*/
public List polygonToCellAddresses(
@@ -530,10 +588,10 @@ public List polygonToCellAddresses(
}
/**
- * Finds indexes within the given geofence.
+ * Finds indexes within the given geopolygon.
*
- * @param points Outline geofence
- * @param holes Geofences of any internal holes
+ * @param points Outline geopolygon
+ * @param holes Geopolygon of any internal holes
* @param res Resolution of the desired indexes
* @throws IllegalArgumentException Invalid resolution
*/
diff --git a/src/main/java/com/uber/h3core/NativeMethods.java b/src/main/java/com/uber/h3core/NativeMethods.java
index 92547ac..42c53fb 100644
--- a/src/main/java/com/uber/h3core/NativeMethods.java
+++ b/src/main/java/com/uber/h3core/NativeMethods.java
@@ -66,6 +66,12 @@ final class NativeMethods {
native void gridPathCells(long start, long end, long[] results);
+ native long maxPolygonToCellsSizeExperimental(
+ double[] verts, int[] holeSizes, double[] holeVerts, int res, int flags);
+
+ native void polygonToCellsExperimental(
+ double[] verts, int[] holeSizes, double[] holeVerts, int res, int flags, long[] results);
+
native long maxPolygonToCellsSize(
double[] verts, int[] holeSizes, double[] holeVerts, int res, int flags);
diff --git a/src/main/java/com/uber/h3core/PolygonToCellsFlags.java b/src/main/java/com/uber/h3core/PolygonToCellsFlags.java
new file mode 100644
index 0000000..7c6bdd7
--- /dev/null
+++ b/src/main/java/com/uber/h3core/PolygonToCellsFlags.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2024 Uber Technologies, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.uber.h3core;
+
+/** Flags for polygonToCellsExperimental */
+public enum PolygonToCellsFlags {
+ /** Cell center is contained in the shape */
+ containment_center(0),
+ /** Cell is fully contained in the shape */
+ containment_full(1),
+ /** Cell overlaps the shape at any point */
+ containment_overlapping(2),
+ /** Cell bounding box overlaps shape */
+ containment_overlapping_bbox(3);
+
+ private final int value;
+
+ PolygonToCellsFlags(int value) {
+ this.value = value;
+ }
+
+ public int toInt() {
+ return this.value;
+ }
+}
diff --git a/src/test/java/com/uber/h3core/TestBindingCompleteness.java b/src/test/java/com/uber/h3core/TestBindingCompleteness.java
index bd401ae..810a4b4 100644
--- a/src/test/java/com/uber/h3core/TestBindingCompleteness.java
+++ b/src/test/java/com/uber/h3core/TestBindingCompleteness.java
@@ -33,7 +33,10 @@ class TestBindingCompleteness {
private static final Set WHITELIST =
ImmutableSet.of(
// These are provided by the Java library (java.lang.Math)
- "degsToRads", "radsToDegs");
+ "degsToRads",
+ "radsToDegs",
+ // Handled by H3Exception
+ "describeH3Error");
@Test
@DisabledInNativeImage
diff --git a/src/test/java/com/uber/h3core/TestRegion.java b/src/test/java/com/uber/h3core/TestRegion.java
index c00869e..fac83d8 100644
--- a/src/test/java/com/uber/h3core/TestRegion.java
+++ b/src/test/java/com/uber/h3core/TestRegion.java
@@ -29,6 +29,96 @@
/** Tests for region (polyfill, h3SetToMultiPolygon) functions. */
class TestRegion extends BaseTestH3Core {
+ @Test
+ void polyfillExperimentalCenter() {
+ List hexagons =
+ h3.polygonToCellsExperimental(
+ ImmutableList.of(
+ new LatLng(37.813318999983238, -122.4089866999972145),
+ new LatLng(37.7866302000007224, -122.3805436999997056),
+ new LatLng(37.7198061999978478, -122.3544736999993603),
+ new LatLng(37.7076131999975672, -122.5123436999983966),
+ new LatLng(37.7835871999971715, -122.5247187000021967),
+ new LatLng(37.8151571999998453, -122.4798767000009008)),
+ null,
+ PolygonToCellsFlags.containment_center,
+ 9);
+
+ assertTrue(hexagons.size() > 1000);
+ }
+
+ @Test
+ void polyfillExperimentalFull() {
+ List hexagons =
+ h3.polygonToCellsExperimental(
+ ImmutableList.of(
+ new LatLng(37.813318999983238, -122.4089866999972145),
+ new LatLng(37.7866302000007224, -122.3805436999997056),
+ new LatLng(37.7198061999978478, -122.3544736999993603),
+ new LatLng(37.7076131999975672, -122.5123436999983966),
+ new LatLng(37.7835871999971715, -122.5247187000021967),
+ new LatLng(37.8151571999998453, -122.4798767000009008)),
+ null,
+ PolygonToCellsFlags.containment_full,
+ 9);
+
+ assertTrue(hexagons.size() > 1000);
+ }
+
+ @Test
+ void polyfillExperimentalOverlapping() {
+ List hexagons =
+ h3.polygonToCellsExperimental(
+ ImmutableList.of(
+ new LatLng(37.813318999983238, -122.4089866999972145),
+ new LatLng(37.7866302000007224, -122.3805436999997056),
+ new LatLng(37.7198061999978478, -122.3544736999993603),
+ new LatLng(37.7076131999975672, -122.5123436999983966),
+ new LatLng(37.7835871999971715, -122.5247187000021967),
+ new LatLng(37.8151571999998453, -122.4798767000009008)),
+ null,
+ PolygonToCellsFlags.containment_overlapping,
+ 9);
+
+ assertTrue(hexagons.size() > 1000);
+ }
+
+ @Test
+ void polyfillExperimentalOverlappingBbox() {
+ List hexagons =
+ h3.polygonToCellsExperimental(
+ ImmutableList.of(
+ new LatLng(37.813318999983238, -122.4089866999972145),
+ new LatLng(37.7866302000007224, -122.3805436999997056),
+ new LatLng(37.7198061999978478, -122.3544736999993603),
+ new LatLng(37.7076131999975672, -122.5123436999983966),
+ new LatLng(37.7835871999971715, -122.5247187000021967),
+ new LatLng(37.8151571999998453, -122.4798767000009008)),
+ null,
+ PolygonToCellsFlags.containment_overlapping_bbox,
+ 9);
+
+ assertTrue(hexagons.size() > 1000);
+ }
+
+ @Test
+ void polyfillExperimental() {
+ List hexagons =
+ h3.polygonToCellsExperimental(
+ ImmutableList.of(
+ new LatLng(37.813318999983238, -122.4089866999972145),
+ new LatLng(37.7866302000007224, -122.3805436999997056),
+ new LatLng(37.7198061999978478, -122.3544736999993603),
+ new LatLng(37.7076131999975672, -122.5123436999983966),
+ new LatLng(37.7835871999971715, -122.5247187000021967),
+ new LatLng(37.8151571999998453, -122.4798767000009008)),
+ null,
+ PolygonToCellsFlags.containment_center,
+ 9);
+
+ assertTrue(hexagons.size() > 1000);
+ }
+
@Test
void polyfill() {
List hexagons =