{@code {"rings":[[[x,y],...]...]}} → {@link Polygon} or {@link MultiPolygon}
+ *
+ *
+ *
If a {@code "spatialReference":{"wkid":N}} object is present the SRID is set on
+ * the returned geometry.
+ *
+ * @param json the Esri JSON string; must not be {@code null}
+ * @return the parsed JTS geometry, or {@code null} if the string cannot be parsed
+ */
+ public static Geometry esriJsonToGeometry(String json) {
+ if (json == null || json.isEmpty()) {
+ return null;
+ }
+
+ JsonNode root;
+ try {
+ root = OBJECT_MAPPER.readTree(json);
+ } catch (IOException e) {
+ return null;
+ }
+
+ if (!root.isObject()) {
+ return null;
+ }
+
+ int wkid = parseSrid(root);
+ Geometry geom;
+
+ if (root.has("x")) {
+ geom = parsePoint(root);
+ } else if (root.has("points")) {
+ geom = parseMultiPoint(root);
+ } else if (root.has("paths")) {
+ geom = parsePaths(root);
+ } else if (root.has("rings")) {
+ geom = parseRings(root);
+ } else {
+ return null;
+ }
+
+ if (geom != null && wkid != 0) {
+ geom.setSRID(wkid);
+ }
+ return geom;
+ }
+
+ private static int parseSrid(JsonNode root) {
+ JsonNode sr = root.get("spatialReference");
+ if (sr != null && sr.has("wkid")) {
+ return sr.get("wkid").asInt(0);
+ }
+ return 0;
+ }
+
+ private static Point parsePoint(JsonNode root) {
+ double x = root.get("x").asDouble();
+ double y = root.get("y").asDouble();
+ Coordinate coord;
+ if (root.has("z")) {
+ coord = new Coordinate(x, y, root.get("z").asDouble());
+ } else {
+ coord = new Coordinate(x, y);
+ }
+ return GeometryUtils.GEOMETRY_FACTORY.createPoint(coord);
+ }
+
+ private static MultiPoint parseMultiPoint(JsonNode root) {
+ JsonNode pts = root.get("points");
+ if (!pts.isArray()) {
+ return null;
+ }
+ Coordinate[] coords = readCoordArray(pts);
+ return GeometryUtils.GEOMETRY_FACTORY.createMultiPointFromCoords(coords);
+ }
+
+ private static Geometry parsePaths(JsonNode root) {
+ JsonNode paths = root.get("paths");
+ if (!paths.isArray() || paths.isEmpty()) {
+ return null;
+ }
+ LineString[] lines = new LineString[paths.size()];
+ for (int i = 0; i < paths.size(); i++) {
+ Coordinate[] coords = readCoordArray(paths.get(i));
+ lines[i] = GeometryUtils.GEOMETRY_FACTORY.createLineString(coords);
+ }
+ if (lines.length == 1) {
+ return lines[0];
+ }
+ return GeometryUtils.GEOMETRY_FACTORY.createMultiLineString(lines);
+ }
+
+ /**
+ * Parses an Esri JSON "rings" array into a {@link Polygon} or {@link MultiPolygon}.
+ *
+ *
Strategy: iterate rings; a ring is an exterior ring if it is CW (positive signed
+ * area using the Shoelace formula in screen-coordinate convention, which is what Esri
+ * uses). Each exterior ring starts a new polygon; CCW rings that follow are holes of
+ * the preceding exterior ring.
+ *
+ *
In practice we use {@link Orientation#isCCW} to classify: a ring that is not
+ * CCW (i.e. is CW) is treated as an exterior ring.
+ */
+ private static Geometry parseRings(JsonNode root) {
+ JsonNode rings = root.get("rings");
+ if (!rings.isArray() || rings.isEmpty()) {
+ return null;
+ }
+
+ // Build list of (coords, isExterior) pairs
+ List exteriors = new ArrayList<>();
+ // holes[i] is the list of hole coordinate arrays for exteriors.get(i)
+ List> holes = new ArrayList<>();
+
+ for (int i = 0; i < rings.size(); i++) {
+ Coordinate[] coords = readCoordArray(rings.get(i));
+ // Ensure the ring is closed
+ coords = ensureClosed(coords);
+
+ // In Esri JSON: exterior rings are CW, interior (holes) are CCW.
+ // Orientation.isCCW returns true for CCW rings.
+ boolean isCCW = Orientation.isCCW(coords);
+ if (!isCCW) {
+ // CW → exterior ring
+ exteriors.add(coords);
+ holes.add(new ArrayList<>());
+ } else {
+ // CCW → hole belonging to the most recent exterior ring
+ if (exteriors.isEmpty()) {
+ // Defensive: treat as exterior if no preceding exterior ring found
+ exteriors.add(coords);
+ holes.add(new ArrayList<>());
+ } else {
+ holes.get(holes.size() - 1).add(coords);
+ }
+ }
+ }
+
+ if (exteriors.isEmpty()) {
+ return null;
+ }
+
+ Polygon[] polygons = new Polygon[exteriors.size()];
+ for (int i = 0; i < exteriors.size(); i++) {
+ LinearRing shell = GeometryUtils.GEOMETRY_FACTORY.createLinearRing(exteriors.get(i));
+ List holeList = holes.get(i);
+ LinearRing[] holeRings = new LinearRing[holeList.size()];
+ for (int h = 0; h < holeList.size(); h++) {
+ holeRings[h] = GeometryUtils.GEOMETRY_FACTORY.createLinearRing(holeList.get(h));
+ }
+ polygons[i] = GeometryUtils.GEOMETRY_FACTORY.createPolygon(shell, holeRings);
+ }
+
+ if (polygons.length == 1) {
+ return polygons[0];
+ }
+ return GeometryUtils.GEOMETRY_FACTORY.createMultiPolygon(polygons);
+ }
+
+ /**
+ * Reads a JSON array-of-arrays into a {@link Coordinate} array.
+ * Each element must be {@code [x, y]} or {@code [x, y, z]}.
+ */
+ private static Coordinate[] readCoordArray(JsonNode array) {
+ Coordinate[] coords = new Coordinate[array.size()];
+ for (int i = 0; i < array.size(); i++) {
+ JsonNode pt = array.get(i);
+ double x = pt.get(0).asDouble();
+ double y = pt.get(1).asDouble();
+ if (pt.size() >= 3) {
+ coords[i] = new Coordinate(x, y, pt.get(2).asDouble());
+ } else {
+ coords[i] = new Coordinate(x, y);
+ }
+ }
+ return coords;
+ }
+
+ /**
+ * Returns a coordinate array that is guaranteed to be closed (first == last).
+ * If the input is already closed it is returned unchanged; otherwise a new array
+ * with the first coordinate appended at the end is returned.
+ */
+ private static Coordinate[] ensureClosed(Coordinate[] coords) {
+ if (coords.length == 0) {
+ return coords;
+ }
+ Coordinate first = coords[0];
+ Coordinate last = coords[coords.length - 1];
+ if (first.equals3D(last)) {
+ return coords;
+ }
+ Coordinate[] closed = Arrays.copyOf(coords, coords.length + 1);
+ closed[coords.length] = first.copy();
+ return closed;
+ }
+}
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/EsriShapeConverter.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/EsriShapeConverter.java
new file mode 100644
index 000000000000..a5eaf7c59a74
--- /dev/null
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/EsriShapeConverter.java
@@ -0,0 +1,588 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.hadoop.hive.ql.udf.esri;
+
+import org.locationtech.jts.algorithm.Orientation;
+import org.locationtech.jts.geom.Coordinate;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.GeometryCollection;
+import org.locationtech.jts.geom.LinearRing;
+import org.locationtech.jts.geom.LineString;
+import org.locationtech.jts.geom.MultiLineString;
+import org.locationtech.jts.geom.MultiPoint;
+import org.locationtech.jts.geom.MultiPolygon;
+import org.locationtech.jts.geom.Point;
+import org.locationtech.jts.geom.Polygon;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Reads and writes raw ESRI shape binary format directly from/to JTS geometries,
+ * without any dependency on the ESRI Geometry library.
+ *
+ *
All binary values are little-endian as per the ESRI shape format specification.
+ *
+ *
Supported shape types:
+ *
+ *
0 - Null/Unknown
+ *
1 - Point
+ *
3 - Polyline (paths)
+ *
5 - Polygon (rings)
+ *
8 - MultiPoint
+ *
11 - PointZ
+ *
13 - PolylineZ
+ *
15 - PolygonZ
+ *
18 - MultiPointZ
+ *
+ */
+public final class EsriShapeConverter {
+
+ private static final int TYPE_NULL = 0;
+ private static final int TYPE_POINT = 1;
+ private static final int TYPE_POLYLINE = 3;
+ private static final int TYPE_POLYGON = 5;
+ private static final int TYPE_MULTIPOINT = 8;
+ private static final int TYPE_POINT_Z = 11;
+ private static final int TYPE_POLYLINE_Z = 13;
+ private static final int TYPE_POLYGON_Z = 15;
+ private static final int TYPE_MULTIPOINT_Z = 18;
+
+ private EsriShapeConverter() {
+ }
+
+ /**
+ * Reads the ESRI shape binary from {@code shapeBuffer} (already positioned at start,
+ * little-endian byte order will be set internally) and returns a JTS {@link Geometry}.
+ *
+ * @param shapeBuffer buffer containing raw ESRI shape bytes starting at its current position
+ * @return a JTS Geometry, or {@code null} for the Null/Unknown shape type
+ * @throws IllegalArgumentException if the buffer contains an unsupported or malformed shape
+ */
+ public static Geometry fromEsriShape(ByteBuffer shapeBuffer) {
+ shapeBuffer.order(ByteOrder.LITTLE_ENDIAN);
+ int shapeType = shapeBuffer.getInt();
+
+ return switch (shapeType) {
+ case TYPE_NULL -> null;
+ case TYPE_POINT -> readPoint(shapeBuffer, false);
+ case TYPE_POINT_Z -> readPoint(shapeBuffer, true);
+ case TYPE_MULTIPOINT -> readMultiPoint(shapeBuffer, false);
+ case TYPE_MULTIPOINT_Z -> readMultiPoint(shapeBuffer, true);
+ case TYPE_POLYLINE -> readPolyline(shapeBuffer, false);
+ case TYPE_POLYLINE_Z -> readPolyline(shapeBuffer, true);
+ case TYPE_POLYGON -> readPolygon(shapeBuffer, false);
+ case TYPE_POLYGON_Z -> readPolygon(shapeBuffer, true);
+ default -> throw new IllegalArgumentException("Unsupported ESRI shape type: " + shapeType);
+ };
+ }
+
+ private static Point readPoint(ByteBuffer buf, boolean hasZ) {
+ double x = buf.getDouble();
+ double y = buf.getDouble();
+ if (hasZ) {
+ double z = buf.getDouble();
+ return GeometryUtils.GEOMETRY_FACTORY.createPoint(new Coordinate(x, y, z));
+ }
+ return GeometryUtils.GEOMETRY_FACTORY.createPoint(new Coordinate(x, y));
+ }
+
+ private static MultiPoint readMultiPoint(ByteBuffer buf, boolean hasZ) {
+ // skip bounding box (4 doubles = 32 bytes)
+ buf.position(buf.position() + 32);
+ int numPoints = buf.getInt();
+ double[] xs = new double[numPoints];
+ double[] ys = new double[numPoints];
+ for (int i = 0; i < numPoints; i++) {
+ xs[i] = buf.getDouble();
+ ys[i] = buf.getDouble();
+ }
+ double[] zs = null;
+ if (hasZ) {
+ // skip zMin, zMax
+ buf.position(buf.position() + 16);
+ zs = new double[numPoints];
+ for (int i = 0; i < numPoints; i++) {
+ zs[i] = buf.getDouble();
+ }
+ }
+ Point[] points = new Point[numPoints];
+ for (int i = 0; i < numPoints; i++) {
+ Coordinate coord = (zs != null) ? new Coordinate(xs[i], ys[i], zs[i])
+ : new Coordinate(xs[i], ys[i]);
+ points[i] = GeometryUtils.GEOMETRY_FACTORY.createPoint(coord);
+ }
+ return GeometryUtils.GEOMETRY_FACTORY.createMultiPoint(points);
+ }
+
+ /**
+ * Read a Polyline or PolylineZ. Buffer is positioned just after the type int.
+ * Multiple parts become a MultiLineString; a single part becomes a LineString.
+ */
+ private static Geometry readPolyline(ByteBuffer buf, boolean hasZ) {
+ // skip bounding box
+ buf.position(buf.position() + 32);
+ int numParts = buf.getInt();
+ int numPoints = buf.getInt();
+
+ int[] partStarts = new int[numParts];
+ for (int i = 0; i < numParts; i++) {
+ partStarts[i] = buf.getInt();
+ }
+
+ Coordinate[] allCoords = readXYCoords(buf, numPoints);
+ if (hasZ) {
+ readZIntoCoords(buf, allCoords);
+ }
+
+ LineString[] lines = new LineString[numParts];
+ for (int i = 0; i < numParts; i++) {
+ int start = partStarts[i];
+ int end = (i + 1 < numParts) ? partStarts[i + 1] : numPoints;
+ Coordinate[] partCoords = copyRange(allCoords, start, end);
+ lines[i] = GeometryUtils.GEOMETRY_FACTORY.createLineString(partCoords);
+ }
+
+ if (lines.length == 1) {
+ return lines[0];
+ }
+ return GeometryUtils.GEOMETRY_FACTORY.createMultiLineString(lines);
+ }
+
+ /**
+ * Read a Polygon or PolygonZ. Buffer is positioned just after the type int.
+ *
+ *
In ESRI shape format, exterior rings are wound clockwise (negative signed area)
+ * and holes are wound counterclockwise (positive signed area). Multiple exterior rings
+ * produce a MultiPolygon.
+ */
+ private static Geometry readPolygon(ByteBuffer buf, boolean hasZ) {
+ // skip bounding box
+ buf.position(buf.position() + 32);
+ int numParts = buf.getInt();
+ int numPoints = buf.getInt();
+
+ int[] partStarts = new int[numParts];
+ for (int i = 0; i < numParts; i++) {
+ partStarts[i] = buf.getInt();
+ }
+
+ Coordinate[] allCoords = readXYCoords(buf, numPoints);
+ if (hasZ) {
+ readZIntoCoords(buf, allCoords);
+ }
+
+ // Split into per-ring coordinate arrays
+ Coordinate[][] rings = new Coordinate[numParts][];
+ for (int i = 0; i < numParts; i++) {
+ int start = partStarts[i];
+ int end = (i + 1 < numParts) ? partStarts[i + 1] : numPoints;
+ rings[i] = copyRange(allCoords, start, end);
+ }
+
+ // Classify rings: clockwise = exterior (ESRI convention); CCW = hole
+ // Build list of (exterior ring index, list of hole ring indices)
+ List exteriorIndices = new ArrayList<>();
+ List> holesByExterior = new ArrayList<>();
+
+ for (int i = 0; i < rings.length; i++) {
+ if (!Orientation.isCCW(rings[i])) {
+ // clockwise -> exterior
+ exteriorIndices.add(i);
+ holesByExterior.add(new ArrayList<>());
+ }
+ }
+
+ // Assign holes to the nearest preceding exterior ring
+ int exteriorCount = exteriorIndices.size();
+ for (int i = 0; i < rings.length; i++) {
+ if (Orientation.isCCW(rings[i])) {
+ // counterclockwise -> hole; assign to the last exterior ring that precedes it
+ int ownerSlot = exteriorCount - 1;
+ for (int e = 0; e < exteriorCount; e++) {
+ if (exteriorIndices.get(e) > i) {
+ ownerSlot = e - 1;
+ break;
+ }
+ }
+ if (ownerSlot < 0) {
+ ownerSlot = 0;
+ }
+ holesByExterior.get(ownerSlot).add(i);
+ }
+ }
+
+ // Build JTS Polygons
+ Polygon[] polygons = new Polygon[exteriorCount];
+ for (int e = 0; e < exteriorCount; e++) {
+ LinearRing shell = GeometryUtils.GEOMETRY_FACTORY.createLinearRing(rings[exteriorIndices.get(e)]);
+ List holeIndices = holesByExterior.get(e);
+ LinearRing[] holes = new LinearRing[holeIndices.size()];
+ for (int h = 0; h < holes.length; h++) {
+ holes[h] = GeometryUtils.GEOMETRY_FACTORY.createLinearRing(rings[holeIndices.get(h)]);
+ }
+ polygons[e] = GeometryUtils.GEOMETRY_FACTORY.createPolygon(shell, holes);
+ }
+
+ if (polygons.length == 1) {
+ return polygons[0];
+ }
+ return GeometryUtils.GEOMETRY_FACTORY.createMultiPolygon(polygons);
+ }
+
+ /**
+ * Writes the JTS {@link Geometry} to ESRI shape binary format and returns the bytes.
+ * All values are little-endian.
+ *
+ * @param geom the JTS geometry to serialize; if {@code null} a 4-byte null shape is returned
+ * @return raw ESRI shape bytes
+ * @throws IllegalArgumentException if the geometry type is not supported
+ */
+ public static byte[] toEsriShape(Geometry geom) {
+ if (geom == null || geom.isEmpty()) {
+ ByteBuffer buf = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN);
+ buf.putInt(TYPE_NULL);
+ return buf.array();
+ }
+
+ return switch (geom.getGeometryType()) {
+ case "Point" -> writePoint((Point) geom);
+ case "MultiPoint" -> writeMultiPoint((MultiPoint) geom);
+ case "LineString", "LinearRing" -> writeLineString((LineString) geom);
+ case "MultiLineString" -> writeMultiLineString((MultiLineString) geom);
+ case "Polygon" -> writePolygonBuffer(collectPolygonRings((Polygon) geom));
+ case "MultiPolygon" -> writeMultiPolygonShape((MultiPolygon) geom);
+ case "GeometryCollection" -> writeGeometryCollection((GeometryCollection) geom);
+ default -> throw new IllegalArgumentException("Unsupported geometry type: " + geom.getGeometryType());
+ };
+ }
+
+ private static byte[] writeLineString(LineString ls) {
+ Coordinate[] coords = ls.getCoordinates();
+ Coordinate[][] parts = {coords};
+ return writePolylineBuffer(parts, coordsHaveZ(coords));
+ }
+
+ private static byte[] writeMultiLineString(MultiLineString mls) {
+ Coordinate[][] parts = new Coordinate[mls.getNumGeometries()][];
+ boolean hasZ = false;
+ for (int i = 0; i < parts.length; i++) {
+ parts[i] = mls.getGeometryN(i).getCoordinates();
+ if (!hasZ && coordsHaveZ(parts[i])) {
+ hasZ = true;
+ }
+ }
+ return writePolylineBuffer(parts, hasZ);
+ }
+
+ private static byte[] writeMultiPolygonShape(MultiPolygon mp) {
+ List allRings = new ArrayList<>();
+ for (int i = 0; i < mp.getNumGeometries(); i++) {
+ allRings.addAll(collectPolygonRings((Polygon) mp.getGeometryN(i)));
+ }
+ return writePolygonBuffer(allRings);
+ }
+
+ private static byte[] writeGeometryCollection(GeometryCollection gc) {
+ if (gc.getNumGeometries() == 0) {
+ ByteBuffer buf = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN);
+ buf.putInt(TYPE_NULL);
+ return buf.array();
+ }
+ throw new IllegalArgumentException(
+ "Heterogeneous GeometryCollection is not supported by ESRI shape format");
+ }
+
+ private static byte[] writePoint(Point point) {
+ Coordinate c = point.getCoordinate();
+ boolean hasZ = !Double.isNaN(c.getZ());
+ if (hasZ) {
+ ByteBuffer buf = ByteBuffer.allocate(4 + 8 + 8 + 8).order(ByteOrder.LITTLE_ENDIAN);
+ buf.putInt(TYPE_POINT_Z);
+ buf.putDouble(c.getX());
+ buf.putDouble(c.getY());
+ buf.putDouble(c.getZ());
+ return buf.array();
+ } else {
+ ByteBuffer buf = ByteBuffer.allocate(4 + 8 + 8).order(ByteOrder.LITTLE_ENDIAN);
+ buf.putInt(TYPE_POINT);
+ buf.putDouble(c.getX());
+ buf.putDouble(c.getY());
+ return buf.array();
+ }
+ }
+
+ private static byte[] writeMultiPoint(MultiPoint mp) {
+ int n = mp.getNumGeometries();
+ Coordinate[] coords = new Coordinate[n];
+ for (int i = 0; i < n; i++) {
+ coords[i] = mp.getGeometryN(i).getCoordinate();
+ }
+ boolean hasZ = coordsHaveZ(coords);
+
+ double[] bbox = bbox2D(coords);
+ // type(4) + bbox(32) + numPoints(4) + points*16 [+ zMin+zMax(16) + n*8 if Z]
+ int baseSize = 4 + 32 + 4 + n * 16;
+ int size = hasZ ? baseSize + 16 + n * 8 : baseSize;
+ int shapeType = hasZ ? TYPE_MULTIPOINT_Z : TYPE_MULTIPOINT;
+
+ ByteBuffer buf = ByteBuffer.allocate(size).order(ByteOrder.LITTLE_ENDIAN);
+ buf.putInt(shapeType);
+ writeBbox(buf, bbox);
+ buf.putInt(n);
+ for (Coordinate c : coords) {
+ buf.putDouble(c.getX());
+ buf.putDouble(c.getY());
+ }
+ if (hasZ) {
+ writeZSection(buf, coords);
+ }
+ return buf.array();
+ }
+
+ /**
+ * Write Polyline (type 3 or 13) from an array of coordinate rings/paths.
+ */
+ private static byte[] writePolylineBuffer(Coordinate[][] parts, boolean hasZ) {
+ int numParts = parts.length;
+ int numPoints = 0;
+ for (Coordinate[] part : parts) {
+ numPoints += part.length;
+ }
+
+ Coordinate[] allCoords = flattenParts(parts);
+ double[] bbox = bbox2D(allCoords);
+ int shapeType = hasZ ? TYPE_POLYLINE_Z : TYPE_POLYLINE;
+
+ // type(4) + bbox(32) + numParts(4) + numPoints(4) + parts*4 + points*16 [+ Z section]
+ int baseSize = 4 + 32 + 4 + 4 + numParts * 4 + numPoints * 16;
+ int size = hasZ ? baseSize + 16 + numPoints * 8 : baseSize;
+
+ ByteBuffer buf = ByteBuffer.allocate(size).order(ByteOrder.LITTLE_ENDIAN);
+ buf.putInt(shapeType);
+ writeBbox(buf, bbox);
+ buf.putInt(numParts);
+ buf.putInt(numPoints);
+
+ int offset = 0;
+ for (Coordinate[] part : parts) {
+ buf.putInt(offset);
+ offset += part.length;
+ }
+ for (Coordinate c : allCoords) {
+ buf.putDouble(c.getX());
+ buf.putDouble(c.getY());
+ }
+ if (hasZ) {
+ writeZSection(buf, allCoords);
+ }
+ return buf.array();
+ }
+
+ /**
+ * Collect all rings from a Polygon as Coordinate arrays, ensuring exterior rings are
+ * clockwise and holes are counterclockwise (ESRI convention).
+ */
+ private static List collectPolygonRings(Polygon polygon) {
+ List rings = new ArrayList<>();
+ Coordinate[] shellCoords = polygon.getExteriorRing().getCoordinates();
+ // Exterior ring must be clockwise (ESRI convention)
+ if (Orientation.isCCW(shellCoords)) {
+ shellCoords = reverse(shellCoords);
+ }
+ rings.add(shellCoords);
+
+ for (int h = 0; h < polygon.getNumInteriorRing(); h++) {
+ Coordinate[] holeCoords = polygon.getInteriorRingN(h).getCoordinates();
+ // Hole must be counterclockwise (ESRI convention)
+ if (!Orientation.isCCW(holeCoords)) {
+ holeCoords = reverse(holeCoords);
+ }
+ rings.add(holeCoords);
+ }
+ return rings;
+ }
+
+ /**
+ * Write Polygon (type 5 or 15) from a list of ring coordinate arrays.
+ * The first ring in each polygon group must be the exterior (clockwise), followed by
+ * its holes (counterclockwise). This method accepts already-oriented rings.
+ */
+ private static byte[] writePolygonBuffer(List rings) {
+ int numParts = rings.size();
+ int numPoints = 0;
+ for (Coordinate[] ring : rings) {
+ numPoints += ring.length;
+ }
+
+ Coordinate[] allCoords = new Coordinate[numPoints];
+ int pos = 0;
+ for (Coordinate[] ring : rings) {
+ System.arraycopy(ring, 0, allCoords, pos, ring.length);
+ pos += ring.length;
+ }
+
+ boolean hasZ = coordsHaveZ(allCoords);
+ double[] bbox = bbox2D(allCoords);
+ int shapeType = hasZ ? TYPE_POLYGON_Z : TYPE_POLYGON;
+
+ int baseSize = 4 + 32 + 4 + 4 + numParts * 4 + numPoints * 16;
+ int size = hasZ ? baseSize + 16 + numPoints * 8 : baseSize;
+
+ ByteBuffer buf = ByteBuffer.allocate(size).order(ByteOrder.LITTLE_ENDIAN);
+ buf.putInt(shapeType);
+ writeBbox(buf, bbox);
+ buf.putInt(numParts);
+ buf.putInt(numPoints);
+
+ int offset = 0;
+ for (Coordinate[] ring : rings) {
+ buf.putInt(offset);
+ offset += ring.length;
+ }
+ for (Coordinate c : allCoords) {
+ buf.putDouble(c.getX());
+ buf.putDouble(c.getY());
+ }
+ if (hasZ) {
+ writeZSection(buf, allCoords);
+ }
+ return buf.array();
+ }
+
+ /** Write a 4-double bounding box into {@code buf}. */
+ private static void writeBbox(ByteBuffer buf, double[] bbox) {
+ buf.putDouble(bbox[0]); // xmin
+ buf.putDouble(bbox[1]); // ymin
+ buf.putDouble(bbox[2]); // xmax
+ buf.putDouble(bbox[3]); // ymax
+ }
+
+ /**
+ * Write the Z section: zMin (double), zMax (double), then one Z per coordinate.
+ * NaN Z values are written as 0.0.
+ */
+ private static void writeZSection(ByteBuffer buf, Coordinate[] coords) {
+ double zMin = Double.MAX_VALUE;
+ double zMax = -Double.MAX_VALUE;
+ for (Coordinate c : coords) {
+ double z = Double.isNaN(c.getZ()) ? 0.0 : c.getZ();
+ if (z < zMin) {
+ zMin = z;
+ }
+ if (z > zMax) {
+ zMax = z;
+ }
+ }
+ buf.putDouble(zMin);
+ buf.putDouble(zMax);
+ for (Coordinate c : coords) {
+ buf.putDouble(Double.isNaN(c.getZ()) ? 0.0 : c.getZ());
+ }
+ }
+
+ /** Reverse a coordinate array (returns a new array, does not modify the original). */
+ private static Coordinate[] reverse(Coordinate[] coords) {
+ Coordinate[] reversed = new Coordinate[coords.length];
+ for (int i = 0; i < coords.length; i++) {
+ reversed[i] = coords[coords.length - 1 - i];
+ }
+ return reversed;
+ }
+
+ /** Return true if any coordinate in the array has a non-NaN Z value. */
+ private static boolean coordsHaveZ(Coordinate[] coords) {
+ for (Coordinate c : coords) {
+ if (!Double.isNaN(c.getZ())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Compute [xmin, ymin, xmax, ymax] bounding box from coordinates.
+ * Ignores Z.
+ */
+ private static double[] bbox2D(Coordinate[] coords) {
+ double xmin = Double.MAX_VALUE;
+ double ymin = Double.MAX_VALUE;
+ double xmax = -Double.MAX_VALUE;
+ double ymax = -Double.MAX_VALUE;
+ for (Coordinate c : coords) {
+ if (c.getX() < xmin) {
+ xmin = c.getX();
+ }
+ if (c.getX() > xmax) {
+ xmax = c.getX();
+ }
+ if (c.getY() < ymin) {
+ ymin = c.getY();
+ }
+ if (c.getY() > ymax) {
+ ymax = c.getY();
+ }
+ }
+ return new double[] {xmin, ymin, xmax, ymax};
+ }
+
+ /** Read {@code n} (x, y) coordinate pairs from {@code buf} into a Coordinate array. */
+ private static Coordinate[] readXYCoords(ByteBuffer buf, int n) {
+ Coordinate[] coords = new Coordinate[n];
+ for (int i = 0; i < n; i++) {
+ coords[i] = new Coordinate(buf.getDouble(), buf.getDouble());
+ }
+ return coords;
+ }
+
+ /**
+ * Read Z values from {@code buf} into an existing coordinate array.
+ * Skips zMin and zMax (2 doubles) before reading the per-coordinate Z values.
+ */
+ private static void readZIntoCoords(ByteBuffer buf, Coordinate[] coords) {
+ // skip zMin, zMax
+ buf.position(buf.position() + 16);
+ for (Coordinate coord : coords) {
+ coord.setZ(buf.getDouble());
+ }
+ }
+
+ /** Copy a slice of a coordinate array. */
+ private static Coordinate[] copyRange(Coordinate[] src, int from, int to) {
+ Coordinate[] dst = new Coordinate[to - from];
+ System.arraycopy(src, from, dst, 0, to - from);
+ return dst;
+ }
+
+ /** Flatten an array of coordinate arrays into a single coordinate array. */
+ private static Coordinate[] flattenParts(Coordinate[][] parts) {
+ int total = 0;
+ for (Coordinate[] part : parts) {
+ total += part.length;
+ }
+ Coordinate[] all = new Coordinate[total];
+ int pos = 0;
+ for (Coordinate[] part : parts) {
+ System.arraycopy(part, 0, all, pos, part.length);
+ pos += part.length;
+ }
+ return all;
+ }
+}
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/GeometryUtils.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/GeometryUtils.java
index fc7279e3655d..c73da63333c9 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/GeometryUtils.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/GeometryUtils.java
@@ -17,29 +17,211 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.Geometry;
-import com.esri.core.geometry.GeometryEngine;
-import com.esri.core.geometry.MapGeometry;
-import com.esri.core.geometry.OperatorImportFromESRIShape;
-import com.esri.core.geometry.Polygon;
-import com.esri.core.geometry.SpatialReference;
-import com.esri.core.geometry.ogc.OGCGeometry;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.WritableBinaryObjectInspector;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.algorithm.Orientation;
+import org.locationtech.jts.geom.CoordinateSequence;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.GeometryCollection;
+import org.locationtech.jts.geom.GeometryFactory;
+import org.locationtech.jts.geom.LineString;
+import org.locationtech.jts.geom.LinearRing;
+import org.locationtech.jts.geom.MultiPolygon;
+import org.locationtech.jts.geom.Point;
+import org.locationtech.jts.geom.Polygon;
+import org.locationtech.jts.io.Ordinate;
+import org.locationtech.jts.io.ParseException;
+import org.locationtech.jts.io.WKBReader;
+import org.locationtech.jts.io.WKBWriter;
+import org.locationtech.jts.io.WKTReader;
+import org.locationtech.jts.io.WKTWriter;
+import org.locationtech.jts.io.geojson.GeoJsonReader;
+import org.locationtech.jts.io.geojson.GeoJsonWriter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
+import java.util.Arrays;
+import java.util.Set;
public class GeometryUtils {
+ private static final Logger LOG = LoggerFactory.getLogger(GeometryUtils.class);
+
private static final int SIZE_WKID = 4;
private static final int SIZE_TYPE = 1;
public static final int WKID_UNKNOWN = 0;
+ // Magic byte at offset 4 to distinguish new WKB format from old ESRI format.
+ // Old format stores OGC type tag (0-6) at byte 4; 0xFF is outside that range.
+ public static final byte NEW_FORMAT_MAGIC = (byte) 0xFF;
+
+ public static final GeometryFactory GEOMETRY_FACTORY = new GeometryFactory();
+
+ // ThreadLocal JTS readers/writers to avoid per-row allocation overhead.
+ // These classes are not thread-safe, so ThreadLocal provides safe reuse
+ // across millions of rows within the same task thread.
+ private static final ThreadLocal WKB_READER =
+ ThreadLocal.withInitial(() -> new WKBReader(GEOMETRY_FACTORY));
+ private static final ThreadLocal WKB_WRITER =
+ ThreadLocal.withInitial(WKBWriter::new);
+ private static final ThreadLocal WKB_WRITER_3D =
+ ThreadLocal.withInitial(() -> new WKBWriter(3));
+ private static final ThreadLocal WKB_WRITER_XYM = ThreadLocal.withInitial(() -> {
+ WKBWriter w = new WKBWriter(3);
+ w.setOutputOrdinates(Ordinate.createXYM());
+ return w;
+ });
+ private static final ThreadLocal WKB_WRITER_4D =
+ ThreadLocal.withInitial(() -> new WKBWriter(4));
+ private static final ThreadLocal WKT_READER =
+ ThreadLocal.withInitial(() -> new WKTReader(GEOMETRY_FACTORY));
+ private static final ThreadLocal WKT_WRITER =
+ ThreadLocal.withInitial(WKTWriter::new);
+ private static final ThreadLocal WKT_WRITER_3D =
+ ThreadLocal.withInitial(() -> new WKTWriter(3));
+ private static final ThreadLocal WKT_WRITER_XYM = ThreadLocal.withInitial(() -> {
+ WKTWriter w = new WKTWriter(3);
+ w.setOutputOrdinates(Ordinate.createXYM());
+ return w;
+ });
+ private static final ThreadLocal WKT_WRITER_4D =
+ ThreadLocal.withInitial(() -> new WKTWriter(4));
+ private static final ThreadLocal GEOJSON_READER =
+ ThreadLocal.withInitial(GeoJsonReader::new);
+ private static final ThreadLocal GEOJSON_WRITER =
+ ThreadLocal.withInitial(GeoJsonWriter::new);
+
+ /** Get the thread-local WKBReader instance (reused across rows). */
+ public static WKBReader wkbReader() {
+ return WKB_READER.get();
+ }
+
+ /** Get the thread-local WKBWriter instance (reused across rows). */
+ public static WKBWriter wkbWriter() {
+ return WKB_WRITER.get();
+ }
+
+ /** Get the thread-local WKTReader instance (reused across rows). */
+ public static WKTReader wktReader() {
+ return WKT_READER.get();
+ }
+
+ /** Get the thread-local WKTWriter instance (reused across rows). */
+ public static WKTWriter wktWriter() {
+ return WKT_WRITER.get();
+ }
+
+ /** Get a dimension-aware WKBWriter that matches the geometry's coordinate type. */
+ public static WKBWriter wkbWriterFor(Geometry geom) {
+ Set ordinates = getOrdinates(geom);
+ if (ordinates.contains(Ordinate.Z) && ordinates.contains(Ordinate.M)) {
+ return WKB_WRITER_4D.get();
+ } else if (ordinates.contains(Ordinate.Z)) {
+ return WKB_WRITER_3D.get();
+ } else if (ordinates.contains(Ordinate.M)) {
+ return WKB_WRITER_XYM.get();
+ }
+ return WKB_WRITER.get();
+ }
+
+ /** Get a dimension-aware WKTWriter that matches the geometry's coordinate type. */
+ public static WKTWriter wktWriterFor(Geometry geom) {
+ Set ordinates = getOrdinates(geom);
+ if (ordinates.contains(Ordinate.Z) && ordinates.contains(Ordinate.M)) {
+ return WKT_WRITER_4D.get();
+ } else if (ordinates.contains(Ordinate.Z)) {
+ return WKT_WRITER_3D.get();
+ } else if (ordinates.contains(Ordinate.M)) {
+ return WKT_WRITER_XYM.get();
+ }
+ return WKT_WRITER.get();
+ }
+
+ /**
+ * Determine the output ordinates present in a geometry by inspecting
+ * its coordinate sequences. Also validates that Z values are not NaN,
+ * since JTS base Coordinate class reports dimension=3 even for 2D points.
+ */
+ public static Set getOrdinates(Geometry geom) {
+ CoordinateSequence seq = getFirstCoordinateSequence(geom);
+ if (seq == null || seq.size() == 0) {
+ return Ordinate.createXY();
+ }
+ boolean hasZ = seq.hasZ() && !Double.isNaN(seq.getZ(0));
+ boolean hasM = seq.hasM();
+ if (hasZ && hasM) {
+ return Ordinate.createXYZM();
+ } else if (hasZ) {
+ return Ordinate.createXYZ();
+ } else if (hasM) {
+ return Ordinate.createXYM();
+ }
+ return Ordinate.createXY();
+ }
+
+ /**
+ * Get the first non-empty CoordinateSequence from a geometry.
+ */
+ private static CoordinateSequence getFirstCoordinateSequence(Geometry geom) {
+ if (geom == null || geom.isEmpty()) {
+ return null;
+ }
+ if (geom instanceof Point point) {
+ return point.getCoordinateSequence();
+ }
+ if (geom instanceof LineString lineString) {
+ return lineString.getCoordinateSequence();
+ }
+ if (geom instanceof Polygon polygon) {
+ return polygon.getExteriorRing().getCoordinateSequence();
+ }
+ if (geom instanceof GeometryCollection) {
+ for (int i = 0; i < geom.getNumGeometries(); i++) {
+ CoordinateSequence seq = getFirstCoordinateSequence(geom.getGeometryN(i));
+ if (seq != null) {
+ return seq;
+ }
+ }
+ }
+ return null;
+ }
+
+ /** Get the thread-local GeoJsonReader instance (reused across rows). */
+ public static GeoJsonReader geoJsonReader() {
+ return GEOJSON_READER.get();
+ }
+
+ /** Get the thread-local GeoJsonWriter instance (reused across rows). */
+ public static GeoJsonWriter geoJsonWriter() {
+ return GEOJSON_WRITER.get();
+ }
+
+ /**
+ * Remove all ThreadLocal reader/writer instances for the current thread.
+ * Call this during UDF close() to prevent memory leaks in long-lived
+ * thread pools (e.g., HiveServer2 fetch tasks, constant folding).
+ */
+ public static void cleanup() {
+ WKB_READER.remove();
+ WKB_WRITER.remove();
+ WKB_WRITER_3D.remove();
+ WKB_WRITER_XYM.remove();
+ WKB_WRITER_4D.remove();
+ WKT_READER.remove();
+ WKT_WRITER.remove();
+ WKT_WRITER_3D.remove();
+ WKT_WRITER_XYM.remove();
+ WKT_WRITER_4D.remove();
+ GEOJSON_READER.remove();
+ GEOJSON_WRITER.remove();
+ }
+
public enum OGCType {
UNKNOWN(0),
ST_POINT(1),
@@ -67,258 +249,321 @@ public int getIndex() {
public static final WritableBinaryObjectInspector geometryTransportObjectInspector =
PrimitiveObjectInspectorFactory.writableBinaryObjectInspector;
- private static final Cache geometryCache = CacheBuilder.newBuilder().weakKeys().build();
+ private static final Cache GEOMETRY_CACHE =
+ CacheBuilder.newBuilder().maximumSize(1024).build();
+
+ /**
+ * Detect whether the given bytes use the new WKB format.
+ */
+ public static boolean isNewFormat(BytesWritable geomref) {
+ return geomref != null && geomref.getLength() > 4 && geomref.getBytes()[4] == NEW_FORMAT_MAGIC;
+ }
/**
- * @param geomref1
- * @param geomref2
- * @return return true if both geometries are in the same spatial reference
+ * Compare spatial references of two geometry byte arrays.
*/
public static boolean compareSpatialReferences(BytesWritable geomref1, BytesWritable geomref2) {
return getWKID(geomref1) == getWKID(geomref2);
}
- public static BytesWritable geometryToEsriShapeBytesWritable(MapGeometry mapGeometry) {
- return serialize(mapGeometry);
+ /**
+ * Serialize a JTS Geometry to the new WKB wire format.
+ * Normalizes polygon ring orientation to OGC standard (exterior CCW, interior CW).
+ */
+ public static BytesWritable geometryToEsriShapeBytesWritable(Geometry geometry) {
+ if (geometry == null) {
+ return null;
+ }
+ geometry = normalizeRingOrientation(geometry);
+ return new CachedGeometryBytesWritable(geometry);
}
- public static BytesWritable geometryToEsriShapeBytesWritable(Geometry geometry, int wkid, OGCType type) {
- return serialize(geometry, wkid, type);
+ /**
+ * Serialize a JTS Geometry with a specific SRID.
+ * Normalizes polygon ring orientation to OGC standard (exterior CCW, interior CW).
+ */
+ public static BytesWritable geometryToEsriShapeBytesWritable(Geometry geometry, int wkid) {
+ if (geometry == null) {
+ return null;
+ }
+ geometry = normalizeRingOrientation(geometry);
+ geometry.setSRID(wkid);
+ return new CachedGeometryBytesWritable(geometry);
}
- public static BytesWritable geometryToEsriShapeBytesWritable(OGCGeometry geometry) {
- return new CachedGeometryBytesWritable(geometry);
+ /**
+ * Normalize polygon ring orientation to OGC standard:
+ * exterior rings counter-clockwise (CCW), interior rings clockwise (CW).
+ * Non-polygon geometries are returned unchanged.
+ */
+ public static Geometry normalizeRingOrientation(Geometry geom) {
+ if (geom instanceof Polygon polygon) {
+ return normalizePolygonRings(polygon);
+ } else if (geom instanceof MultiPolygon mp) {
+ Polygon[] polys = new Polygon[mp.getNumGeometries()];
+ for (int i = 0; i < mp.getNumGeometries(); i++) {
+ polys[i] = normalizePolygonRings((Polygon) mp.getGeometryN(i));
+ }
+ MultiPolygon result = geom.getFactory().createMultiPolygon(polys);
+ result.setSRID(geom.getSRID());
+ return result;
+ }
+ return geom;
}
- public static OGCGeometry geometryFromEsriShape(BytesWritable geomref) {
- // always assume bytes are recycled and can't be cached by using
- // geomref.getBytes() as the key
- return geometryFromEsriShape(geomref, true);
+ private static Polygon normalizePolygonRings(Polygon polygon) {
+ GeometryFactory factory = polygon.getFactory();
+ LinearRing shell = polygon.getExteriorRing();
+
+ // Exterior ring should be CCW
+ boolean shellChanged = false;
+ if (shell.getNumPoints() >= 4 && !Orientation.isCCW(shell.getCoordinateSequence())) {
+ shell = shell.reverse();
+ shellChanged = true;
+ }
+
+ // Interior rings should be CW (not CCW)
+ int numHoles = polygon.getNumInteriorRing();
+ LinearRing[] holes = new LinearRing[numHoles];
+ boolean holesChanged = false;
+ for (int i = 0; i < numHoles; i++) {
+ LinearRing hole = polygon.getInteriorRingN(i);
+ if (hole.getNumPoints() >= 4 && Orientation.isCCW(hole.getCoordinateSequence())) {
+ holes[i] = hole.reverse();
+ holesChanged = true;
+ } else {
+ holes[i] = hole;
+ }
+ }
+
+ if (!shellChanged && !holesChanged) {
+ return polygon;
+ }
+
+ Polygon result = factory.createPolygon(shell, holes);
+ result.setSRID(polygon.getSRID());
+ return result;
}
- public static OGCGeometry geometryFromEsriShape(BytesWritable geomref, boolean bytesRecycled) {
+ /**
+ * Deserialize geometry bytes (either old ESRI format or new WKB format) to a JTS Geometry.
+ */
+ public static Geometry geometryFromEsriShape(BytesWritable geomref) {
+ return geometryFromEsriShape(geomref, true);
+ }
+ /**
+ * Deserialize geometry bytes to a JTS Geometry.
+ * @param geomref the geometry bytes
+ * @param bytesRecycled true if the bytes backing the writable may be reused (disables caching)
+ */
+ public static Geometry geometryFromEsriShape(BytesWritable geomref, boolean bytesRecycled) {
if (geomref == null) {
return null;
}
- // this geomref might actually be a LazyGeometryBytesWritable which
- // means we don't need to deserialize from bytes
- if (geomref instanceof CachedGeometryBytesWritable) {
- return ((CachedGeometryBytesWritable) geomref).getGeometry();
+ if (geomref instanceof CachedGeometryBytesWritable cached) {
+ return cached.getGeometry();
}
- // if geomref bytes are recycled, we can't use the cache because every
- // key in the cache will be the same byte array
if (!bytesRecycled) {
- // check for a cache hit to previously created geometries
- OGCGeometry cachedGeom = geometryCache.getIfPresent(geomref);
-
+ Geometry cachedGeom = GEOMETRY_CACHE.getIfPresent(geomref);
if (cachedGeom != null) {
return cachedGeom;
}
}
- // not in cache or instance of CachedGeometryBytesWritable. now
- // need to create the geometry from its bytes
- int wkid = getWKID(geomref);
- ByteBuffer shapeBuffer = getShapeByteBuffer(geomref);
+ int length = geomref.getLength();
+ byte[] bytes = geomref.getBytes();
- //minimum for a shape, even an empty one, is the 4 byte type record
- if (shapeBuffer.limit() < 4) {
+ if (length < 5) {
return null;
+ }
+
+ Geometry geom;
+ int srid;
+
+ if (bytes[4] == NEW_FORMAT_MAGIC) {
+ // New WKB format: bytes 0-3 = SRID (big-endian), byte 4 = 0xFF, bytes 5+ = WKB
+ srid = ((bytes[0] & 0xFF) << 24) | ((bytes[1] & 0xFF) << 16)
+ | ((bytes[2] & 0xFF) << 8) | (bytes[3] & 0xFF);
+ byte[] wkb = Arrays.copyOfRange(bytes, 5, length);
+ try {
+ geom = wkbReader().read(wkb);
+ } catch (ParseException e) {
+ LOG.warn("Failed to parse WKB geometry", e);
+ return null;
+ }
} else {
- if (shapeBuffer.getInt(0) == Geometry.Type.Unknown.value()) { //empty Geometry, intentional
+ // Old ESRI format: bytes 0-3 = WKID (little-endian), byte 4 = OGC type (0-6), bytes 5+ = ESRI shape
+ srid = ByteBuffer.wrap(bytes, 0, 4).order(ByteOrder.LITTLE_ENDIAN).getInt();
+ ByteBuffer shapeBuffer = ByteBuffer.wrap(bytes, SIZE_WKID + SIZE_TYPE, length - SIZE_WKID - SIZE_TYPE)
+ .slice().order(ByteOrder.LITTLE_ENDIAN);
+
+ if (shapeBuffer.limit() < 4) {
return null;
- } else {
- SpatialReference spatialReference = null;
- if (wkid != GeometryUtils.WKID_UNKNOWN) {
- spatialReference = SpatialReference.create(wkid);
- }
+ }
- Geometry esriGeom = OperatorImportFromESRIShape.local().execute(0, Geometry.Type.Unknown, shapeBuffer);
- OGCGeometry createdGeom = OGCGeometry.createFromEsriGeometry(esriGeom, spatialReference);
+ // Check if shape type is Unknown (empty geometry)
+ if (shapeBuffer.getInt(0) == 0) {
+ return null;
+ }
- if (!bytesRecycled) {
- // only add bytes to cache if we know they aren't being recycled
- geometryCache.put(geomref, createdGeom);
- }
+ // Use native EsriShapeConverter to read the old ESRI shape format
+ try {
+ geom = EsriShapeConverter.fromEsriShape(shapeBuffer);
+ } catch (Exception e) {
+ LOG.warn("Failed to parse ESRI shape geometry", e);
+ return null;
+ }
+ }
- return createdGeom;
+ if (geom != null) {
+ geom.setSRID(srid);
+ if (!bytesRecycled) {
+ GEOMETRY_CACHE.put(geomref, geom);
}
}
+
+ return geom;
}
/**
- * Gets the geometry type for the given hive geometry bytes
- *
- * @param geomref reference to hive geometry bytes
- * @return OGCType set in the 5th byte of the hive geometry bytes
+ * Gets the geometry type for the given hive geometry bytes.
+ * For new WKB format, reads the type directly from the WKB header
+ * without full deserialization.
*/
public static OGCType getType(BytesWritable geomref) {
- // SIZE_WKID is the offset to the byte that stores the type information
- return OGCTypeLookup[geomref.getBytes()[SIZE_WKID]];
+ if (geomref == null || geomref.getLength() < 5) {
+ return OGCType.UNKNOWN;
+ }
+ byte[] bytes = geomref.getBytes();
+ if (bytes[4] == NEW_FORMAT_MAGIC) {
+ // New format: bytes 5+ are WKB. WKB layout: byte 5 = byte order,
+ // bytes 6-9 = geometry type int (in the indicated byte order).
+ if (geomref.getLength() < 10) {
+ return OGCType.UNKNOWN;
+ }
+ ByteOrder order = (bytes[5] == 1) ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN;
+ int wkbType = ByteBuffer.wrap(bytes, 6, 4).order(order).getInt();
+ // JTS uses extended WKB: bit 31 (0x80000000) = Z, bit 30 (0x40000000) = M,
+ // bit 29 (0x20000000) = SRID. Strip these flag bits to get the base type.
+ // Also handle ISO WKB encoding (type + 1000/2000/3000) for compatibility.
+ int baseType = wkbType & 0x1FFFFFFF; // strip Z/M/SRID flag bits
+ if (baseType >= 1000) {
+ baseType = baseType % 1000; // ISO WKB encoding
+ }
+ return switch (baseType) {
+ case 1 -> OGCType.ST_POINT;
+ case 2 -> OGCType.ST_LINESTRING;
+ case 3 -> OGCType.ST_POLYGON;
+ case 4 -> OGCType.ST_MULTIPOINT;
+ case 5 -> OGCType.ST_MULTILINESTRING;
+ case 6 -> OGCType.ST_MULTIPOLYGON;
+ default -> OGCType.UNKNOWN;
+ };
+ }
+ int typeIdx = bytes[SIZE_WKID] & 0xFF;
+ if (typeIdx >= OGCTypeLookup.length) {
+ return OGCType.UNKNOWN;
+ }
+ return OGCTypeLookup[typeIdx];
}
/**
- * Sets the geometry type (in place) for the given hive geometry bytes
- * @param geomref reference to hive geometry bytes
- * @param type OGC geometry type
+ * Infer OGCType from a JTS Geometry.
*/
- public static void setType(BytesWritable geomref, OGCType type) {
- geomref.getBytes()[SIZE_WKID] = (byte) type.getIndex();
+ public static OGCType inferOGCType(Geometry geom) {
+ if (geom == null) {
+ return OGCType.UNKNOWN;
+ }
+ return switch (geom.getGeometryType()) {
+ case "Point" -> OGCType.ST_POINT;
+ case "LineString", "LinearRing" -> OGCType.ST_LINESTRING;
+ case "Polygon" -> OGCType.ST_POLYGON;
+ case "MultiPoint" -> OGCType.ST_MULTIPOINT;
+ case "MultiLineString" -> OGCType.ST_MULTILINESTRING;
+ case "MultiPolygon" -> OGCType.ST_MULTIPOLYGON;
+ default -> OGCType.UNKNOWN;
+ };
}
/**
- * Gets the WKID for the given hive geometry bytes
- *
- * @param geomref reference to hive geometry bytes
- * @return WKID set in the first 4 bytes of the hive geometry bytes
+ * Gets the WKID/SRID for the given hive geometry bytes.
*/
public static int getWKID(BytesWritable geomref) {
- ByteBuffer bb = ByteBuffer.wrap(geomref.getBytes());
- return bb.getInt(0);
+ if (geomref == null || geomref.getLength() < 4) {
+ return WKID_UNKNOWN;
+ }
+ byte[] bytes = geomref.getBytes();
+ if (geomref.getLength() > 4 && bytes[4] == NEW_FORMAT_MAGIC) {
+ // New format: big-endian SRID
+ return ((bytes[0] & 0xFF) << 24) | ((bytes[1] & 0xFF) << 16)
+ | ((bytes[2] & 0xFF) << 8) | (bytes[3] & 0xFF);
+ } else {
+ // Old format: little-endian WKID
+ return ByteBuffer.wrap(bytes, 0, 4).order(ByteOrder.LITTLE_ENDIAN).getInt();
+ }
}
/**
- * Sets the WKID (in place) for the given hive geometry bytes
- *
- * @param geomref reference to hive geometry bytes
- * @param wkid
+ * Sets the WKID/SRID (in place) for the given hive geometry bytes.
*/
public static void setWKID(BytesWritable geomref, int wkid) {
- ByteBuffer bb = ByteBuffer.allocate(4);
- bb.putInt(wkid);
- System.arraycopy(bb.array(), 0, geomref.getBytes(), 0, SIZE_WKID);
- }
-
- public static OGCType getInferredOGCType(Geometry geom) {
- switch (geom.getType()) {
- case Polygon:
- Polygon poly = (Polygon) geom;
- // Number of outer rings defines single vs multi
- int ringCount = poly.getExteriorRingCount();
- if (ringCount == 1) {
- return OGCType.ST_POLYGON;
- } else {
- return OGCType.ST_MULTIPOLYGON;
- }
- case Polyline:
- return OGCType.ST_MULTILINESTRING;
- case MultiPoint:
- return OGCType.ST_MULTIPOINT;
- case Point:
- return OGCType.ST_POINT;
- default:
- return OGCType.UNKNOWN;
- }
- }
-
- private static ByteBuffer getShapeByteBuffer(BytesWritable geomref) {
- byte[] geomBytes = geomref.getBytes();
- int offset = SIZE_WKID + SIZE_TYPE;
-
- return ByteBuffer.wrap(geomBytes, offset, geomBytes.length - offset).slice().order(ByteOrder.LITTLE_ENDIAN);
- }
-
- private static BytesWritable serialize(MapGeometry mapGeometry) {
- int wkid = 0;
-
- SpatialReference spatialRef = mapGeometry.getSpatialReference();
-
- if (spatialRef != null) {
- wkid = spatialRef.getID();
- }
-
- Geometry.Type esriType = mapGeometry.getGeometry().getType();
- OGCType ogcType;
-
- switch (esriType) {
- case Point:
- ogcType = OGCType.ST_POINT;
- break;
- case Polyline:
- ogcType = OGCType.ST_LINESTRING;
- break;
- case Polygon:
- ogcType = OGCType.ST_POLYGON;
- break;
- default:
- ogcType = OGCType.UNKNOWN;
+ byte[] bytes = geomref.getBytes();
+ if (geomref.getLength() > 4 && bytes[4] == NEW_FORMAT_MAGIC) {
+ // New format: big-endian
+ bytes[0] = (byte) (wkid >> 24);
+ bytes[1] = (byte) (wkid >> 16);
+ bytes[2] = (byte) (wkid >> 8);
+ bytes[3] = (byte) wkid;
+ } else {
+ // Old format: little-endian
+ ByteBuffer bb = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN);
+ bb.putInt(wkid);
+ System.arraycopy(bb.array(), 0, bytes, 0, SIZE_WKID);
}
-
- return serialize(mapGeometry.getGeometry(), wkid, ogcType);
}
- private static BytesWritable serialize(OGCGeometry ogcGeometry) {
- int wkid;
- try {
- wkid = ogcGeometry.SRID();
- } catch (NullPointerException npe) {
- wkid = 0;
- }
-
- OGCType ogcType;
- String typeName;
- try {
- typeName = ogcGeometry.geometryType();
-
- if (typeName.equals("Point"))
- ogcType = OGCType.ST_POINT;
- else if (typeName.equals("LineString"))
- ogcType = OGCType.ST_LINESTRING;
- else if (typeName.equals("Polygon"))
- ogcType = OGCType.ST_POLYGON;
- else if (typeName.equals("MultiPoint"))
- ogcType = OGCType.ST_MULTIPOINT;
- else if (typeName.equals("MultiLineString"))
- ogcType = OGCType.ST_MULTILINESTRING;
- else if (typeName.equals("MultiPolygon"))
- ogcType = OGCType.ST_MULTIPOLYGON;
- else
- ogcType = OGCType.UNKNOWN;
- } catch (NullPointerException npe) {
- ogcType = OGCType.UNKNOWN;
- }
-
- return serialize(ogcGeometry.getEsriGeometry(), wkid, ogcType);
- }
-
- private static BytesWritable serialize(Geometry geometry, int wkid, OGCType type) {
+ /**
+ * Serialize a JTS Geometry to the new WKB wire format bytes.
+ * Uses dimension-aware WKBWriter to preserve Z/M coordinates.
+ */
+ private static BytesWritable serializeJts(Geometry geometry) {
if (geometry == null) {
return null;
}
-
- // first get shape buffer for geometry
- byte[] shape = GeometryEngine.geometryToEsriShape(geometry);
-
- if (shape == null) {
- return null;
- }
-
- byte[] shapeWithData = new byte[shape.length + SIZE_WKID + SIZE_TYPE];
-
- System.arraycopy(shape, 0, shapeWithData, SIZE_WKID + SIZE_TYPE, shape.length);
-
- BytesWritable hiveGeometryBytes = new BytesWritable(shapeWithData);
-
- setWKID(hiveGeometryBytes, wkid);
- setType(hiveGeometryBytes, type);
-
- BytesWritable ret = new BytesWritable(shapeWithData);
-
- return ret;
+ int srid = geometry.getSRID();
+ byte[] wkb = wkbWriterFor(geometry).write(geometry);
+
+ byte[] result = new byte[SIZE_WKID + 1 + wkb.length];
+ // Write SRID big-endian
+ result[0] = (byte) (srid >> 24);
+ result[1] = (byte) (srid >> 16);
+ result[2] = (byte) (srid >> 8);
+ result[3] = (byte) srid;
+ // Magic byte
+ result[4] = NEW_FORMAT_MAGIC;
+ // WKB payload
+ System.arraycopy(wkb, 0, result, 5, wkb.length);
+ return new BytesWritable(result);
}
+ /**
+ * A BytesWritable that caches the JTS Geometry to avoid repeated deserialization.
+ */
public static class CachedGeometryBytesWritable extends BytesWritable {
- OGCGeometry cachedGeom;
+ private final Geometry cachedGeom;
- public CachedGeometryBytesWritable(OGCGeometry geom) {
+ public CachedGeometryBytesWritable(Geometry geom) {
cachedGeom = geom;
- super.set(serialize(cachedGeom));
+ BytesWritable serialized = serializeJts(cachedGeom);
+ if (serialized != null) {
+ super.set(serialized);
+ }
}
- public OGCGeometry getGeometry() {
+ public Geometry getGeometry() {
return cachedGeom;
}
}
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/Haversine.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/Haversine.java
index 18fb5db4c96e..dc4718ec9e7c 100644
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/Haversine.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/Haversine.java
@@ -23,7 +23,7 @@
import static java.lang.Math.sqrt;
import static java.lang.Math.toRadians;
-import com.esri.core.geometry.ogc.OGCPoint;
+import org.locationtech.jts.geom.Point;
// Class is based on Apache Sedona code:
// https://github.com/apache/sedona/blob/eee44b509624d9e4022a6dd40d9b07d72a369a20/common/src/main/java/org/apache/sedona/common/sphere/Haversine.java#L43
@@ -56,11 +56,11 @@ public static double distanceMeters(double lon1, double lat1,
return distance(lon1, lat1, lon2, lat2, AVG_EARTH_RADIUS_METERS);
}
- public static double distanceMeters(OGCPoint point1, OGCPoint point2) {
- double lon1 = point1.X();
- double lat1 = point1.Y();
- double lon2 = point2.X();
- double lat2 = point2.Y();
+ public static double distanceMeters(Point point1, Point point2) {
+ double lon1 = point1.getX();
+ double lat1 = point1.getY();
+ double lon2 = point2.getX();
+ double lat2 = point2.getY();
return distanceMeters(lon1, lat1, lon2, lat2);
}
}
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/HiveGeometryOIHelper.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/HiveGeometryOIHelper.java
index f20d582dae25..b6628d3c12b6 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/HiveGeometryOIHelper.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/HiveGeometryOIHelper.java
@@ -17,8 +17,6 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.ogc.OGCGeometry;
-import com.esri.core.geometry.ogc.OGCPoint;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDF.DeferredObject;
@@ -27,6 +25,8 @@
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorUtils;
import org.apache.hadoop.hive.serde2.objectinspector.PrimitiveObjectInspector;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.Point;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -38,7 +38,7 @@ public class HiveGeometryOIHelper {
private final int argIndex;
private final boolean isConstant;
- OGCGeometry constantGeometry;
+ Geometry constantGeometry;
private HiveGeometryOIHelper(ObjectInspector oi, int argIndex) {
this.oi = (PrimitiveObjectInspector) oi;
@@ -62,13 +62,11 @@ public static HiveGeometryOIHelper create(ObjectInspector oi, int argIndex) thro
}
public static boolean canCreate(ObjectInspector oi) {
- return oi.getCategory() == Category.PRIMITIVE;
- }
+ return oi.getCategory() == Category.PRIMITIVE;
+ }
/**
* Gets whether this geometry argument is constant.
- *
- * @return
*/
public boolean isConstant() {
return isConstant;
@@ -76,10 +74,8 @@ public boolean isConstant() {
/**
* Returns the cached constant geometry object.
- *
- * @return cache geometry, or null if not constant
*/
- public OGCGeometry getConstantGeometry() {
+ public Geometry getConstantGeometry() {
return constantGeometry;
}
@@ -88,14 +84,14 @@ public OGCGeometry getConstantGeometry() {
* or returns the cached geometry if argument is constant.
*
* @param args
- * @return OGCPoint or null if not a point
+ * @return Point or null if not a point
* @see #getGeometry(DeferredObject[])
*/
- public OGCPoint getPoint(DeferredObject[] args) {
- OGCGeometry geometry = getGeometry(args);
+ public Point getPoint(DeferredObject[] args) {
+ Geometry geometry = getGeometry(args);
- if (geometry instanceof OGCPoint) {
- return (OGCPoint) geometry;
+ if (geometry instanceof Point point) {
+ return point;
} else {
return null;
}
@@ -104,11 +100,8 @@ public OGCPoint getPoint(DeferredObject[] args) {
/**
* Reads the corresponding geometry from the deferred object list
* or returns the cached geometry if argument is constant.
- *
- * @param args
- * @return
*/
- public OGCGeometry getGeometry(DeferredObject[] args) {
+ public Geometry getGeometry(DeferredObject[] args) {
if (isConstant) {
if (constantGeometry == null) {
constantGeometry = getGeometry(args[argIndex]);
@@ -122,7 +115,7 @@ public OGCGeometry getGeometry(DeferredObject[] args) {
}
}
- private OGCGeometry getGeometry(DeferredObject arg) {
+ private Geometry getGeometry(DeferredObject arg) {
Object writable;
try {
writable = oi.getPrimitiveWritableObject(arg.get());
@@ -139,7 +132,12 @@ private OGCGeometry getGeometry(DeferredObject arg) {
case BINARY:
return getGeometryFromBytes((BytesWritable) writable);
case STRING:
- return OGCGeometry.fromText(writable.toString());
+ try {
+ return GeometryUtils.wktReader().read(writable.toString());
+ } catch (Exception e) {
+ LOG.error("Failed to parse WKT: " + writable.toString(), e);
+ return null;
+ }
default:
return null;
}
@@ -150,7 +148,7 @@ private OGCGeometry getGeometry(DeferredObject arg) {
// always assume bytes are reused until we determine they aren't
private boolean bytesReused = true;
- private OGCGeometry getGeometryFromBytes(BytesWritable writable) {
+ private Geometry getGeometryFromBytes(BytesWritable writable) {
if (bytesReused) {
if (last != null && last != writable) {
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Aggr_ConvexHull.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Aggr_ConvexHull.java
index fcad441604aa..7f4d73e1fc6f 100644
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Aggr_ConvexHull.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Aggr_ConvexHull.java
@@ -17,20 +17,17 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.Geometry;
-import com.esri.core.geometry.GeometryEngine;
-import com.esri.core.geometry.SpatialReference;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDAF;
import org.apache.hadoop.hive.ql.exec.UDAFEvaluator;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.GeometryCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
-import java.util.Collections;
@Description(name = "ST_Aggr_ConvexHull",
value = "_FUNC_(ST_Geometry) - aggregate convex hull of all geometries passed",
@@ -42,9 +39,7 @@ public class ST_Aggr_ConvexHull extends UDAF {
public static class AggrConvexHullBinaryEvaluator implements UDAFEvaluator {
- private final int MAX_BUFFER_SIZE = 1000;
- private final ArrayList geometries = new ArrayList(MAX_BUFFER_SIZE);
- SpatialReference spatialRef = null;
+ private final ArrayList geometries = new ArrayList<>();
int firstWKID = -2;
/*
@@ -52,10 +47,8 @@ public static class AggrConvexHullBinaryEvaluator implements UDAFEvaluator {
*/
@Override
public void init() {
-
- if (geometries.size() > 0) {
- geometries.clear();
- }
+ geometries.clear();
+ firstWKID = -2;
}
/*
@@ -70,17 +63,17 @@ public boolean iterate(BytesWritable geomref) throws HiveException {
if (firstWKID == -2) {
firstWKID = GeometryUtils.getWKID(geomref);
- if (firstWKID != GeometryUtils.WKID_UNKNOWN) {
- spatialRef = SpatialReference.create(firstWKID);
- }
} else if (firstWKID != GeometryUtils.getWKID(geomref)) {
LogUtils.Log_SRIDMismatch(LOG, geomref, firstWKID);
return false;
}
- addGeometryToBuffer(geomref);
+ Geometry geom = GeometryUtils.geometryFromEsriShape(geomref);
+ if (geom != null) {
+ geometries.add(geom);
+ }
- return (geometries.size() != 0);
+ return !geometries.isEmpty();
}
/*
@@ -92,13 +85,22 @@ public boolean merge(BytesWritable other) throws HiveException {
}
public BytesWritable terminatePartial() throws HiveException {
- maybeAggregateBuffer(true);
- if (geometries.size() == 1) {
- OGCGeometry rslt = OGCGeometry.createFromEsriGeometry(geometries.get(0), spatialRef);
- return GeometryUtils.geometryToEsriShapeBytesWritable(rslt);
- } else {
+ if (geometries.isEmpty()) {
return null;
}
+ try {
+ GeometryCollection collection = GeometryUtils.GEOMETRY_FACTORY
+ .createGeometryCollection(geometries.toArray(new Geometry[0]));
+ Geometry result = collection.convexHull();
+ int wkid = (firstWKID == -2) ? GeometryUtils.WKID_UNKNOWN : firstWKID;
+ return GeometryUtils.geometryToEsriShapeBytesWritable(result, wkid);
+ } catch (Exception e) {
+ LOG.error("ST_Aggr_ConvexHull failed", e);
+ } finally {
+ geometries.clear();
+ firstWKID = -2;
+ }
+ return null;
}
/*
@@ -109,36 +111,5 @@ public BytesWritable terminate() throws HiveException {
return terminatePartial();
}
- private void addGeometryToBuffer(BytesWritable geomref) throws HiveException {
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geomref);
- addGeometryToBuffer(ogcGeometry.getEsriGeometry());
- }
-
- private void addGeometryToBuffer(Geometry geom) throws HiveException {
- geometries.add(geom);
- maybeAggregateBuffer(false);
- }
-
- /*
- * If the right conditions are met (or force == true), create a convex hull of the geometries
- * in the current buffer
- */
- private void maybeAggregateBuffer(boolean force) throws HiveException {
-
- if (force || geometries.size() > MAX_BUFFER_SIZE) {
- Geometry[] geomArray = new Geometry[geometries.size()];
- geometries.toArray(geomArray);
- geometries.clear();
-
- try {
- //LOG.trace("performing convexHull");
- Geometry[] convexResult = GeometryEngine.convexHull(geomArray, true);
- Collections.addAll(geometries, convexResult); // expect one
- } catch (Exception e) {
- LOG.error("exception thrown", e);
- }
- }
- }
-
}
}
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Aggr_Intersection.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Aggr_Intersection.java
index 28b18d0bce84..a5323edc64e2 100644
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Aggr_Intersection.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Aggr_Intersection.java
@@ -17,13 +17,12 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.SpatialReference;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDAF;
import org.apache.hadoop.hive.ql.exec.UDAFEvaluator;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -37,8 +36,7 @@ public class ST_Aggr_Intersection extends UDAF {
public static class AggrIntersectionBinaryEvaluator implements UDAFEvaluator {
- private OGCGeometry isectGeom = null;
- SpatialReference spatialRef = null;
+ private Geometry isectGeom = null;
int firstWKID = -2;
/*
@@ -60,27 +58,26 @@ public boolean iterate(BytesWritable geomref) throws HiveException {
if (firstWKID == -2) {
firstWKID = GeometryUtils.getWKID(geomref);
- if (firstWKID != GeometryUtils.WKID_UNKNOWN) {
- spatialRef = SpatialReference.create(firstWKID);
- }
} else if (firstWKID != GeometryUtils.getWKID(geomref)) {
LogUtils.Log_SRIDMismatch(LOG, geomref, firstWKID);
return false;
}
try {
- OGCGeometry rowGeom = GeometryUtils.geometryFromEsriShape(geomref);
- rowGeom.setSpatialReference(spatialRef);
- if (isectGeom == null)
+ Geometry rowGeom = GeometryUtils.geometryFromEsriShape(geomref);
+ if (rowGeom == null) {
+ return false;
+ }
+ if (isectGeom == null) {
isectGeom = rowGeom;
- else
+ } else {
isectGeom = isectGeom.intersection(rowGeom);
+ }
return true;
} catch (Exception e) {
LogUtils.Log_InternalError(LOG, "ST_Aggr_Intersection: " + e);
return false;
}
-
}
/*
@@ -97,9 +94,9 @@ public boolean merge(BytesWritable other) throws HiveException {
public BytesWritable terminatePartial() throws HiveException {
if (isectGeom == null) {
return null;
- } else {
- return GeometryUtils.geometryToEsriShapeBytesWritable(isectGeom);
}
+ int wkid = (firstWKID == -2) ? GeometryUtils.WKID_UNKNOWN : firstWKID;
+ return GeometryUtils.geometryToEsriShapeBytesWritable(isectGeom, wkid);
}
public BytesWritable terminate() throws HiveException {
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Aggr_Union.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Aggr_Union.java
index 3824a51002c2..9178bc39cea5 100644
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Aggr_Union.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Aggr_Union.java
@@ -17,20 +17,19 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.Geometry;
-import com.esri.core.geometry.GeometryCursor;
-import com.esri.core.geometry.ListeningGeometryCursor;
-import com.esri.core.geometry.OperatorUnion;
-import com.esri.core.geometry.SpatialReference;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDAF;
import org.apache.hadoop.hive.ql.exec.UDAFEvaluator;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.operation.union.UnaryUnionOp;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.ArrayList;
+import java.util.List;
+
@Description(name = "ST_Aggr_Union",
value = "_FUNC_(ST_Geometry) - aggregate union of all geometries passed",
extended = "Example:\n" + " SELECT _FUNC_(geometry) FROM source; -- return union of all geometries in source")
@@ -40,10 +39,8 @@ public class ST_Aggr_Union extends UDAF {
public static class AggrUnionBinaryEvaluator implements UDAFEvaluator {
- SpatialReference spatialRef = null;
int firstWKID = -2;
- ListeningGeometryCursor lgc = null; // listening geometry cursor
- GeometryCursor xgc = null; // executing geometry cursor
+ List geomList = new ArrayList<>();
/*
* Initialize evaluator
@@ -62,32 +59,23 @@ public boolean iterate(BytesWritable geomref) throws HiveException {
return false;
}
- if (xgc == null) {
+ if (firstWKID == -2) {
firstWKID = GeometryUtils.getWKID(geomref);
- if (firstWKID != GeometryUtils.WKID_UNKNOWN) {
- spatialRef = SpatialReference.create(firstWKID);
- }
- // Need new geometry cursors both initially and after every terminatePartial(),
- // because the geometry cursors can not be re-used after extracting the
- // unioned geometry with GeometryCursor.next().
- //Create an empty listener.
- lgc = new ListeningGeometryCursor();
- //Obtain union operator - after taking note of spatial reference.
- xgc = OperatorUnion.local().execute(lgc, spatialRef, null);
} else if (firstWKID != GeometryUtils.getWKID(geomref)) {
LogUtils.Log_SRIDMismatch(LOG, geomref, firstWKID);
return false;
}
try {
- lgc.tick(GeometryUtils.geometryFromEsriShape(geomref).getEsriGeometry()); // push
- xgc.tock(); // tock to match tick
+ Geometry geom = GeometryUtils.geometryFromEsriShape(geomref);
+ if (geom != null) {
+ geomList.add(geom);
+ }
return true;
} catch (Exception e) {
LogUtils.Log_InternalError(LOG, "ST_Aggr_Union: " + e);
return false;
}
-
}
/*
@@ -102,14 +90,21 @@ public boolean merge(BytesWritable other) throws HiveException {
* Return a geometry that is the union of all geometries added up until this point
*/
public BytesWritable terminatePartial() throws HiveException {
+ if (geomList.isEmpty()) {
+ return null;
+ }
try {
- Geometry rslt = xgc.next();
- lgc = null; // not reusable
- xgc = null; // not reusable
- OGCGeometry ogeom = OGCGeometry.createFromEsriGeometry(rslt, spatialRef);
- return GeometryUtils.geometryToEsriShapeBytesWritable(ogeom);
+ Geometry result = UnaryUnionOp.union(geomList);
+ if (result == null) {
+ return null;
+ }
+ int wkid = (firstWKID == -2) ? GeometryUtils.WKID_UNKNOWN : firstWKID;
+ return GeometryUtils.geometryToEsriShapeBytesWritable(result, wkid);
} catch (Exception e) {
LogUtils.Log_InternalError(LOG, "ST_Aggr_Union: " + e);
+ } finally {
+ geomList.clear();
+ firstWKID = -2;
}
return null;
}
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Area.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Area.java
index 1c35c2f277a2..e953aaaa1cf5 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Area.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Area.java
@@ -17,10 +17,10 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.serde2.io.DoubleWritable;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -58,13 +58,13 @@ public DoubleWritable evaluate(BytesWritable geomref) {
return null;
}
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geomref);
- if (ogcGeometry == null) {
+ Geometry geom = GeometryUtils.geometryFromEsriShape(geomref);
+ if (geom == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
- resultDouble.set(ogcGeometry.getEsriGeometry().calculateArea2D());
+ resultDouble.set(geom.getArea());
return resultDouble;
}
}
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_AsBinary.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_AsBinary.java
index ec74196e7686..b130c9bfaf0f 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_AsBinary.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_AsBinary.java
@@ -17,14 +17,12 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.nio.ByteBuffer;
-
@Description(name = "ST_AsBinary",
value = "_FUNC_(ST_Geometry) - return Well-Known Binary (WKB) representation of geometry\n",
extended = "Example:\n" + " SELECT _FUNC_(ST_Point(1, 2)) FROM onerow; -- WKB representation of POINT (1 2)\n")
@@ -47,15 +45,14 @@ public BytesWritable evaluate(BytesWritable geomref) {
return null;
}
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geomref);
- if (ogcGeometry == null) {
+ Geometry geom = GeometryUtils.geometryFromEsriShape(geomref);
+ if (geom == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
try {
- ByteBuffer byteBuf = ogcGeometry.asBinary();
- byte[] byteArr = byteBuf.array();
+ byte[] byteArr = GeometryUtils.wkbWriterFor(geom).write(geom);
return new BytesWritable(byteArr);
} catch (Exception e) {
LOG.error(e.getMessage());
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_AsGeoJson.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_AsGeoJson.java
index 88d34e18f7fb..10d1a036b39d 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_AsGeoJson.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_AsGeoJson.java
@@ -17,10 +17,10 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.io.BytesWritable;
import org.apache.hadoop.io.Text;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -31,7 +31,7 @@
+ "Note : \n" + " ST_AsGeoJSON outputs the _geometry_ contents but not _crs_.\n"
+ " ST_AsGeoJSON requires geometry-api-java version 1.1 or later.\n")
//@HivePdkUnitTests(
-// cases = {
+// cases = {
// @HivePdkUnitTest(
// query = "select ST_AsGeoJSON(ST_point(1, 2))) from onerow",
// result = "{\"type\":\"Point\", \"coordinates\":[1.0, 2.0]}"
@@ -57,14 +57,14 @@ public Text evaluate(BytesWritable geomref) {
return null;
}
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geomref);
- if (ogcGeometry == null) {
+ Geometry geom = GeometryUtils.geometryFromEsriShape(geomref);
+ if (geom == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
try {
- String outJson = ogcGeometry.asGeoJson();
+ String outJson = GeometryUtils.geoJsonWriter().write(geom);
resultText.set(outJson);
return resultText;
} catch (Exception e) {
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_AsJson.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_AsJson.java
index 6ae59857432f..02aa0a143f6a 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_AsJson.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_AsJson.java
@@ -17,12 +17,11 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.Geometry;
-import com.esri.core.geometry.GeometryEngine;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.io.BytesWritable;
import org.apache.hadoop.io.Text;
+
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -31,7 +30,7 @@
extended = "Example:\n" + " SELECT _FUNC_(ST_Point(1.0, 2.0)) from onerow; -- {\"x\":1.0,\"y\":2.0}\n"
+ " SELECT _FUNC_(ST_SetSRID(ST_Point(1, 1), 4326)) from onerow; -- {\"x\":1.0,\"y\":1.0,\"spatialReference\":{\"wkid\":4326}}")
//@HivePdkUnitTests(
-// cases = {
+// cases = {
// @HivePdkUnitTest(
// query = "select ST_AsJSON(ST_Point(1, 2)), ST_AsJSON(ST_SetSRID(ST_Point(1, 1), 4326)) from onerow",
// result = "{\"x\":1.0,\"y\":2.0} {\"x\":1.0,\"y\":1.0,\"spatialReference\":{\"wkid\":4326}}"
@@ -55,14 +54,18 @@ public Text evaluate(BytesWritable geomref) {
return null;
}
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geomref);
- if (ogcGeometry == null) {
+ Geometry jtsGeom = GeometryUtils.geometryFromEsriShape(geomref);
+ if (jtsGeom == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
- Geometry esriGeom = ogcGeometry.getEsriGeometry();
- int wkid = GeometryUtils.getWKID(geomref);
- return new Text(GeometryEngine.geometryToJson(wkid, esriGeom));
+ try {
+ int wkid = GeometryUtils.getWKID(geomref);
+ return new Text(EsriJsonConverter.geometryToEsriJson(jtsGeom, wkid));
+ } catch (Exception e) {
+ LOG.error(e.getMessage());
+ return null;
+ }
}
}
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_AsShape.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_AsShape.java
index ece4f69db7a1..8521e9fd7847 100644
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_AsShape.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_AsShape.java
@@ -17,11 +17,10 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.Geometry;
-import com.esri.core.geometry.GeometryEngine;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.io.BytesWritable;
+
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -39,17 +38,14 @@ public BytesWritable evaluate(BytesWritable geomref) {
return null;
}
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geomref);
- if (ogcGeometry == null) {
+ Geometry jtsGeom = GeometryUtils.geometryFromEsriShape(geomref);
+ if (jtsGeom == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
try {
- // Get Esri shape representation
- Geometry esriGeometry = ogcGeometry.getEsriGeometry();
- byte[] esriShape = GeometryEngine.geometryToEsriShape(esriGeometry);
- return new BytesWritable(esriShape);
+ return new BytesWritable(EsriShapeConverter.toEsriShape(jtsGeom));
} catch (Exception e) {
LOG.error(e.getMessage());
return null;
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_AsText.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_AsText.java
index 84be547a74ec..0a56fd3de800 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_AsText.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_AsText.java
@@ -17,13 +17,10 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.GeometryEngine;
-import com.esri.core.geometry.WktExportFlags;
-import com.esri.core.geometry.ogc.OGCGeometry;
-import org.apache.hadoop.hive.ql.udf.esri.GeometryUtils.OGCType;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.io.BytesWritable;
import org.apache.hadoop.io.Text;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -31,7 +28,7 @@
value = "_FUNC_(ST_Geometry) - return Well-Known Text (WKT) representation of ST_Geometry\n",
extended = "Example:\n" + " SELECT _FUNC_(ST_Point(1, 2)) FROM onerow; -- POINT (1 2)\n")
//@HivePdkUnitTests(
-// cases = {
+// cases = {
// @HivePdkUnitTest(
// query = "SELECT ST_AsText(ST_Point(1, 2)), ST_AsText(ST_MultiPoint(1, 2, 3, 4)) FROM onerow",
// result = "POINT (1 2) MULTIPOINT ((1 2), (3 4))"
@@ -60,40 +57,21 @@ public Text evaluate(BytesWritable geomref) {
return null;
}
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geomref);
- if (ogcGeometry == null) {
+ Geometry geom = GeometryUtils.geometryFromEsriShape(geomref);
+ if (geom == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
- int wktExportFlag = getWktExportFlag(GeometryUtils.getType(geomref));
-
try {
- // mind: GeometryType with ST_AsText(ST_GeomFromText('MultiLineString((0 80, 0.03 80.04))'))
- // return new Text(ogcGeometry.asText());
- return new Text(GeometryEngine.geometryToWkt(ogcGeometry.getEsriGeometry(), wktExportFlag));
+ String wkt = GeometryUtils.wktWriterFor(geom).write(geom);
+ // JTS 1.20 WKTWriter omits the space between dimension qualifier and '(' (e.g. "POINT Z(").
+ // ISO WKT requires "POINT Z (" with a space. Fix by inserting a space.
+ wkt = wkt.replace(" ZM(", " ZM (").replace(" Z(", " Z (").replace(" M(", " M (");
+ return new Text(wkt);
} catch (Exception e) {
LOG.error(e.getMessage());
return null;
}
}
-
- private int getWktExportFlag(OGCType type) {
- switch (type) {
- case ST_POLYGON:
- return WktExportFlags.wktExportPolygon;
- case ST_MULTIPOLYGON:
- return WktExportFlags.wktExportMultiPolygon;
- case ST_POINT:
- return WktExportFlags.wktExportPoint;
- case ST_MULTIPOINT:
- return WktExportFlags.wktExportMultiPoint;
- case ST_LINESTRING:
- return WktExportFlags.wktExportLineString;
- case ST_MULTILINESTRING:
- return WktExportFlags.wktExportMultiLineString;
- default:
- return WktExportFlags.wktExportDefaults;
- }
- }
-}
\ No newline at end of file
+}
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Bin.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Bin.java
index 61e5985b0b23..4bd34196c99c 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Bin.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Bin.java
@@ -17,7 +17,6 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.ogc.OGCPoint;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
@@ -29,6 +28,7 @@
import org.apache.hadoop.hive.serde2.objectinspector.PrimitiveObjectInspector.PrimitiveCategory;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorUtils;
+import org.locationtech.jts.geom.Point;
import java.util.EnumSet;
@@ -72,13 +72,13 @@ public Object evaluate(DeferredObject[] args) throws HiveException {
bins = new BinUtils(binSize);
}
- OGCPoint point = geomHelper.getPoint(args);
+ Point point = geomHelper.getPoint(args);
if (point == null) {
return null;
}
- return bins.getId(point.X(), point.Y());
+ return bins.getId(point.getX(), point.getY());
}
@Override
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_BinEnvelope.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_BinEnvelope.java
index 7bab0b2f3334..fc3ef2e3044f 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_BinEnvelope.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_BinEnvelope.java
@@ -17,9 +17,6 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.Envelope;
-import com.esri.core.geometry.ogc.OGCPoint;
-import org.apache.hadoop.hive.ql.udf.esri.GeometryUtils.OGCType;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
@@ -29,6 +26,9 @@
import org.apache.hadoop.hive.serde2.objectinspector.PrimitiveObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.PrimitiveObjectInspector.PrimitiveCategory;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorUtils;
+import org.locationtech.jts.geom.Envelope;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.Point;
import java.util.EnumSet;
@@ -85,7 +85,7 @@ public Object evaluate(DeferredObject[] args) throws HiveException {
bins = new BinUtils(binSize);
}
- Envelope env = new Envelope();
+ Envelope env;
if (oiBinId != null) {
// argument 1 is a number, attempt to get the envelope with bin ID
@@ -95,19 +95,20 @@ public Object evaluate(DeferredObject[] args) throws HiveException {
}
long binId = PrimitiveObjectInspectorUtils.getLong(args[1].get(), oiBinId);
- bins.queryEnvelope(binId, env);
+ env = bins.queryEnvelope(binId);
} else {
// argument 1 is a geometry, attempt to get the envelope with a point
- OGCPoint point = binPoint.getPoint(args);
+ Point point = binPoint.getPoint(args);
if (point == null) {
return null;
}
- bins.queryEnvelope(point.X(), point.Y(), env);
+ env = bins.queryEnvelope(point.getX(), point.getY());
}
- return GeometryUtils.geometryToEsriShapeBytesWritable(env, 0, OGCType.ST_POLYGON);
+ Geometry polygon = GeometryUtils.GEOMETRY_FACTORY.toGeometry(env);
+ return GeometryUtils.geometryToEsriShapeBytesWritable(polygon);
}
@Override
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Boundary.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Boundary.java
index 73d6eee7736e..c869ad58f4f0 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Boundary.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Boundary.java
@@ -17,10 +17,11 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.ogc.OGCGeometry;
-import com.esri.core.geometry.ogc.OGCMultiLineString;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.LinearRing;
+import org.locationtech.jts.geom.MultiLineString;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -55,15 +56,21 @@ public BytesWritable evaluate(BytesWritable geomref) {
return null;
}
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geomref);
- if (ogcGeometry == null) {
+ Geometry geom = GeometryUtils.geometryFromEsriShape(geomref);
+ if (geom == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
try {
- OGCGeometry boundGeom = ogcGeometry.boundary();
- if (boundGeom.geometryType().equals("MultiLineString") && ((OGCMultiLineString) boundGeom).numGeometries() == 1)
- boundGeom = ((OGCMultiLineString) boundGeom).geometryN(0); // match ST_Boundary/SQL-RDBMS
+ Geometry boundGeom = geom.getBoundary();
+ // match ST_Boundary/SQL-RDBMS: unwrap a single-geometry MultiLineString to LineString
+ if (boundGeom instanceof MultiLineString && boundGeom.getNumGeometries() == 1) {
+ boundGeom = boundGeom.getGeometryN(0);
+ }
+ // JTS returns LinearRing for polygon boundary; OGC standard requires LineString
+ if (boundGeom instanceof LinearRing linearRing) {
+ boundGeom = geom.getFactory().createLineString(linearRing.getCoordinateSequence());
+ }
return GeometryUtils.geometryToEsriShapeBytesWritable(boundGeom);
} catch (Exception e) {
LogUtils.Log_InternalError(LOG, "ST_Boundary: " + e);
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Buffer.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Buffer.java
index 98f395bbb045..7dbca66a2382 100644
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Buffer.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Buffer.java
@@ -17,10 +17,10 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.serde2.io.DoubleWritable;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -37,14 +37,13 @@ public BytesWritable evaluate(BytesWritable geometryref1, DoubleWritable distanc
return null;
}
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geometryref1);
- if (ogcGeometry == null) {
+ Geometry geom = GeometryUtils.geometryFromEsriShape(geometryref1);
+ if (geom == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
- OGCGeometry bufferedGeometry = ogcGeometry.buffer(distance.get());
- // TODO persist type information (polygon vs multipolygon)
+ Geometry bufferedGeometry = geom.buffer(distance.get(), 24);
return GeometryUtils.geometryToEsriShapeBytesWritable(bufferedGeometry);
}
}
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Centroid.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Centroid.java
index 430134fe8f3c..4b641340cd6d 100644
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Centroid.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Centroid.java
@@ -17,9 +17,9 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -41,13 +41,13 @@ public BytesWritable evaluate(BytesWritable geomref) {
return null;
}
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geomref);
- if (ogcGeometry == null) {
+ Geometry geom = GeometryUtils.geometryFromEsriShape(geomref);
+ if (geom == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
- return GeometryUtils.geometryToEsriShapeBytesWritable(ogcGeometry.centroid());
+ return GeometryUtils.geometryToEsriShapeBytesWritable(geom.getCentroid());
}
}
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Contains.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Contains.java
index bc0d58a9d4cd..f41d096afaa5 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Contains.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Contains.java
@@ -17,10 +17,10 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.OperatorContains;
-import com.esri.core.geometry.OperatorSimpleRelation;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.udf.UDFType;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.prep.PreparedGeometry;
@UDFType(deterministic = true) @Description(name = "ST_Contains",
value = "_FUNC_(geometry1, geometry2) - return true if geometry1 contains geometry2",
@@ -30,8 +30,13 @@
extends ST_GeometryRelational {
@Override
- protected OperatorSimpleRelation getRelationOperator() {
- return OperatorContains.local();
+ protected boolean executeRelation(Geometry geom1, Geometry geom2) {
+ return geom1.contains(geom2);
+ }
+
+ @Override
+ protected boolean executeRelationPrepared(PreparedGeometry prepGeom1, Geometry geom2) {
+ return prepGeom1.contains(geom2);
}
@Override
@@ -39,4 +44,3 @@ public String getDisplayString(String[] args) {
return String.format("returns true if %s contains %s", args[0], args[1]);
}
}
-
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_ConvexHull.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_ConvexHull.java
index 8371882ace3b..cfb8c5744385 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_ConvexHull.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_ConvexHull.java
@@ -17,12 +17,10 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.Geometry;
-import com.esri.core.geometry.GeometryEngine;
-import com.esri.core.geometry.ogc.OGCGeometry;
-import org.apache.hadoop.hive.ql.udf.esri.GeometryUtils.OGCType;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.GeometryCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -71,38 +69,33 @@ public BytesWritable evaluate(BytesWritable... geomrefs) {
}
}
- // now build geometry array to pass to GeometryEngine.union
+ // build geometry array
Geometry[] geomsToProcess = new Geometry[geomrefs.length];
for (int i = 0; i < geomrefs.length; i++) {
- //HiveGeometry hiveGeometry = GeometryUtils.geometryFromEsriShape(geomrefs[i]);
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geomrefs[i]);
+ Geometry geom = GeometryUtils.geometryFromEsriShape(geomrefs[i]);
- if (ogcGeometry == null) {
+ if (geom == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
- geomsToProcess[i] = ogcGeometry.getEsriGeometry();
+ geomsToProcess[i] = geom;
}
try {
-
- Geometry[] geomResult = GeometryEngine.convexHull(geomsToProcess, true);
-
- if (geomResult.length != 1) {
- return null;
+ Geometry result;
+ if (geomsToProcess.length == 1) {
+ result = geomsToProcess[0].convexHull();
+ } else {
+ GeometryCollection collection =
+ GeometryUtils.GEOMETRY_FACTORY.createGeometryCollection(geomsToProcess);
+ result = collection.convexHull();
}
- Geometry merged = geomResult[0];
-
- // we have to infer the type of the differenced geometry because we don't know
- // if it's going to end up as a single or multi-part geometry
- OGCType inferredType = GeometryUtils.getInferredOGCType(merged);
-
- return GeometryUtils.geometryToEsriShapeBytesWritable(merged, firstWKID, inferredType);
+ return GeometryUtils.geometryToEsriShapeBytesWritable(result, firstWKID);
} catch (Exception e) {
- LogUtils.Log_ExceptionThrown(LOG, "GeometryEngine.convexHull", e);
+ LogUtils.Log_ExceptionThrown(LOG, "ST_ConvexHull", e);
return null;
}
}
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_CoordDim.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_CoordDim.java
index 376628de59cd..120f4c0e5cba 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_CoordDim.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_CoordDim.java
@@ -17,10 +17,11 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.io.BytesWritable;
import org.apache.hadoop.io.IntWritable;
+import org.locationtech.jts.geom.Coordinate;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -60,12 +61,23 @@ public IntWritable evaluate(BytesWritable geomref) {
return null;
}
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geomref);
- if (ogcGeometry == null) {
+ Geometry geom = GeometryUtils.geometryFromEsriShape(geomref);
+ if (geom == null) {
return null;
}
- resultInt.set(ogcGeometry.coordinateDimension());
+ // Infer coordinate dimension: 2 + (hasZ ? 1 : 0) + (hasM ? 1 : 0)
+ Coordinate coord = geom.getCoordinate();
+ int dim = 2;
+ if (coord != null) {
+ if (!Double.isNaN(coord.getZ())) {
+ dim++;
+ }
+ if (!Double.isNaN(coord.getM())) {
+ dim++;
+ }
+ }
+ resultInt.set(dim);
return resultInt;
}
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Crosses.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Crosses.java
index 39d48cabccb6..23aa992cf2b8 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Crosses.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Crosses.java
@@ -17,9 +17,9 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.OperatorCrosses;
-import com.esri.core.geometry.OperatorSimpleRelation;
import org.apache.hadoop.hive.ql.exec.Description;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.prep.PreparedGeometry;
@Description(name = "ST_Crosses",
value = "_FUNC_(geometry1, geometry2) - return true if geometry1 crosses geometry2",
@@ -30,8 +30,13 @@
extends ST_GeometryRelational {
@Override
- protected OperatorSimpleRelation getRelationOperator() {
- return OperatorCrosses.local();
+ protected boolean executeRelation(Geometry geom1, Geometry geom2) {
+ return geom1.crosses(geom2);
+ }
+
+ @Override
+ protected boolean executeRelationPrepared(PreparedGeometry prepGeom1, Geometry geom2) {
+ return prepGeom1.crosses(geom2);
}
@Override
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Difference.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Difference.java
index c8847b119098..539e0c433369 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Difference.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Difference.java
@@ -17,9 +17,9 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -58,18 +58,17 @@ public BytesWritable evaluate(BytesWritable geometryref1, BytesWritable geometry
return null;
}
- OGCGeometry ogcGeom1 = GeometryUtils.geometryFromEsriShape(geometryref1);
- OGCGeometry ogcGeom2 = GeometryUtils.geometryFromEsriShape(geometryref2);
- if (ogcGeom1 == null || ogcGeom2 == null) {
+ Geometry geom1 = GeometryUtils.geometryFromEsriShape(geometryref1);
+ Geometry geom2 = GeometryUtils.geometryFromEsriShape(geometryref2);
+ if (geom1 == null || geom2 == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
- OGCGeometry diffGeometry = ogcGeom1.difference(ogcGeom2);
+ Geometry diffGeometry = geom1.difference(geom2);
// we have to infer the type of the differenced geometry because we don't know
// if it's going to end up as a single or multi-part geometry
- // OGCType inferredType = GeometryUtils.getInferredOGCType(diffGeometry.getEsriGeometry());
return GeometryUtils.geometryToEsriShapeBytesWritable(diffGeometry);
}
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Dimension.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Dimension.java
index 3798b91e882d..54583fe906b6 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Dimension.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Dimension.java
@@ -17,10 +17,10 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.io.BytesWritable;
import org.apache.hadoop.io.IntWritable;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -72,13 +72,13 @@ public IntWritable evaluate(BytesWritable geomref) {
return null;
}
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geomref);
- if (ogcGeometry == null) {
+ Geometry geom = GeometryUtils.geometryFromEsriShape(geomref);
+ if (geom == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
- resultInt.set(ogcGeometry.dimension());
+ resultInt.set(geom.getDimension());
return resultInt;
}
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Disjoint.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Disjoint.java
index 50b70397b114..97ddbebfbc69 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Disjoint.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Disjoint.java
@@ -17,12 +17,12 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.OperatorDisjoint;
-import com.esri.core.geometry.OperatorSimpleRelation;
import org.apache.hadoop.hive.ql.exec.Description;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.prep.PreparedGeometry;
@Description(name = "ST_Disjoint",
- value = "_FUNC_(ST_Geometry1, ST_Geometry2) - return true if ST_Geometry1 intersects ST_Geometry2",
+ value = "_FUNC_(ST_Geometry1, ST_Geometry2) - return true if ST_Geometry1 is disjoint from ST_Geometry2",
extended = "Example:\n"
+ "SELECT _FUNC_(ST_LineString(0,0, 0,1), ST_LineString(1,1, 1,0)) from src LIMIT 1; -- return true\n"
+ "SELECT _FUNC_(ST_LineString(0,0, 1,1), ST_LineString(1,0, 0,1)) from src LIMIT 1; -- return false\n")
@@ -30,8 +30,13 @@
public class ST_Disjoint extends ST_GeometryRelational {
@Override
- protected OperatorSimpleRelation getRelationOperator() {
- return OperatorDisjoint.local();
+ protected boolean executeRelation(Geometry geom1, Geometry geom2) {
+ return geom1.disjoint(geom2);
+ }
+
+ @Override
+ protected boolean executeRelationPrepared(PreparedGeometry prepGeom1, Geometry geom2) {
+ return prepGeom1.disjoint(geom2);
}
@Override
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Distance.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Distance.java
index ff8f80606b85..e56059b34a35 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Distance.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Distance.java
@@ -17,10 +17,10 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.serde2.io.DoubleWritable;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -59,15 +59,15 @@ public DoubleWritable evaluate(BytesWritable geometryref1, BytesWritable geometr
return null;
}
- OGCGeometry ogcGeom1 = GeometryUtils.geometryFromEsriShape(geometryref1);
- OGCGeometry ogcGeom2 = GeometryUtils.geometryFromEsriShape(geometryref2);
- if (ogcGeom1 == null || ogcGeom2 == null) {
+ Geometry geom1 = GeometryUtils.geometryFromEsriShape(geometryref1);
+ Geometry geom2 = GeometryUtils.geometryFromEsriShape(geometryref2);
+ if (geom1 == null || geom2 == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
try {
- resultDouble.set(ogcGeom1.distance(ogcGeom2));
+ resultDouble.set(geom1.distance(geom2));
return resultDouble;
} catch (Exception e) {
LogUtils.Log_InternalError(LOG, "ST_Distance: " + e);
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_DistanceSphere.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_DistanceSphere.java
index 8ea5825952b1..a70397fba309 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_DistanceSphere.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_DistanceSphere.java
@@ -17,12 +17,12 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.ogc.OGCPoint;
-
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.udf.esri.GeometryUtils.OGCType;
import org.apache.hadoop.hive.serde2.io.DoubleWritable;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.Point;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -55,13 +55,16 @@ public DoubleWritable evaluate(BytesWritable geometryref1, BytesWritable geometr
return null;
}
- OGCPoint point1 = (OGCPoint) GeometryUtils.geometryFromEsriShape(geometryref1);
- OGCPoint point2 = (OGCPoint) GeometryUtils.geometryFromEsriShape(geometryref2);
- if (point1 == null || point2 == null) {
+ Geometry geom1 = GeometryUtils.geometryFromEsriShape(geometryref1);
+ Geometry geom2 = GeometryUtils.geometryFromEsriShape(geometryref2);
+ if (geom1 == null || geom2 == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
+ Point point1 = (Point) geom1;
+ Point point2 = (Point) geom2;
+
try {
resultDouble.set(Haversine.distanceMeters(point1, point2));
return resultDouble;
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_EndPoint.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_EndPoint.java
index 637861fdc22a..0a158fb478d6 100644
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_EndPoint.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_EndPoint.java
@@ -17,11 +17,10 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.MultiPath;
-import com.esri.core.geometry.SpatialReference;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.LineString;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -44,21 +43,14 @@ public BytesWritable evaluate(BytesWritable geomref) {
return null;
}
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geomref);
- if (ogcGeometry == null) {
+ Geometry geom = GeometryUtils.geometryFromEsriShape(geomref);
+ if (geom == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
if (GeometryUtils.getType(geomref) == GeometryUtils.OGCType.ST_LINESTRING) {
- MultiPath lines = (MultiPath) (ogcGeometry.getEsriGeometry());
- int wkid = GeometryUtils.getWKID(geomref);
- SpatialReference spatialReference = null;
- if (wkid != GeometryUtils.WKID_UNKNOWN) {
- spatialReference = SpatialReference.create(wkid);
- }
- return GeometryUtils.geometryToEsriShapeBytesWritable(
- OGCGeometry.createFromEsriGeometry(lines.getPoint(lines.getPointCount() - 1), spatialReference));
+ return GeometryUtils.geometryToEsriShapeBytesWritable(((LineString) geom).getEndPoint());
} else {
LogUtils.Log_InvalidType(LOG, GeometryUtils.OGCType.ST_LINESTRING, GeometryUtils.getType(geomref));
return null;
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_EnvIntersects.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_EnvIntersects.java
index 8dbd50baf616..3ac5f9150e07 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_EnvIntersects.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_EnvIntersects.java
@@ -17,12 +17,10 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.Envelope;
-import com.esri.core.geometry.Geometry;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.io.BooleanWritable;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -64,20 +62,14 @@ public BooleanWritable evaluate(BytesWritable geometryref1, BytesWritable geomet
return null;
}
- OGCGeometry ogcGeom1 = GeometryUtils.geometryFromEsriShape(geometryref1);
- OGCGeometry ogcGeom2 = GeometryUtils.geometryFromEsriShape(geometryref2);
- if (ogcGeom1 == null || ogcGeom2 == null) {
+ Geometry geom1 = GeometryUtils.geometryFromEsriShape(geometryref1);
+ Geometry geom2 = GeometryUtils.geometryFromEsriShape(geometryref2);
+ if (geom1 == null || geom2 == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
- Geometry geometry1 = ogcGeom1.getEsriGeometry();
- Geometry geometry2 = ogcGeom2.getEsriGeometry();
- Envelope env1 = new Envelope(), env2 = new Envelope();
- geometry1.queryEnvelope(env1);
- geometry2.queryEnvelope(env2);
-
- resultBoolean.set(env1.isIntersecting(env2));
+ resultBoolean.set(geom1.getEnvelopeInternal().intersects(geom2.getEnvelopeInternal()));
return resultBoolean;
}
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Envelope.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Envelope.java
index 4e2b62f2046c..cacb3fb4603b 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Envelope.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Envelope.java
@@ -17,11 +17,9 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.Envelope;
-import com.esri.core.geometry.SpatialReference;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -58,21 +56,15 @@ public BytesWritable evaluate(BytesWritable geometryref) {
return null;
}
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geometryref);
- if (ogcGeometry == null) {
+ Geometry geom = GeometryUtils.geometryFromEsriShape(geometryref);
+ if (geom == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
int wkid = GeometryUtils.getWKID(geometryref);
- SpatialReference spatialReference = null;
- if (wkid != GeometryUtils.WKID_UNKNOWN) {
- spatialReference = SpatialReference.create(wkid);
- }
- Envelope envBound = new Envelope();
- ogcGeometry.getEsriGeometry().queryEnvelope(envBound);
- return GeometryUtils
- .geometryToEsriShapeBytesWritable(OGCGeometry.createFromEsriGeometry(envBound, spatialReference));
+ Geometry envelope = geom.getEnvelope();
+ return GeometryUtils.geometryToEsriShapeBytesWritable(envelope, wkid);
}
}
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Equals.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Equals.java
index 170d86245415..85225094fb05 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Equals.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Equals.java
@@ -17,9 +17,8 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.OperatorEquals;
-import com.esri.core.geometry.OperatorSimpleRelation;
import org.apache.hadoop.hive.ql.exec.Description;
+import org.locationtech.jts.geom.Geometry;
@Description(name = "ST_Equals",
value = "_FUNC_(geometry1, geometry2) - return true if geometry1 equals geometry2",
@@ -29,8 +28,8 @@
extends ST_GeometryRelational {
@Override
- protected OperatorSimpleRelation getRelationOperator() {
- return OperatorEquals.local();
+ protected boolean executeRelation(Geometry geom1, Geometry geom2) {
+ return geom1.equalsTopo(geom2);
}
@Override
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_ExteriorRing.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_ExteriorRing.java
index 29ba1eee34a5..35c4ebcbef23 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_ExteriorRing.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_ExteriorRing.java
@@ -17,16 +17,14 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.ogc.OGCGeometry;
-import com.esri.core.geometry.ogc.OGCLineString;
-import com.esri.core.geometry.ogc.OGCPolygon;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.LinearRing;
+import org.locationtech.jts.geom.Polygon;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.lang.reflect.Method;
-
@Description(name = "ST_ExteriorRing",
value = "_FUNC_(polygon) - return linestring which is the exterior ring of the polygon",
extended = "Example:\n"
@@ -58,29 +56,17 @@ public BytesWritable evaluate(BytesWritable geomref) {
return null;
}
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geomref);
- if (ogcGeometry == null) {
+ Geometry geom = GeometryUtils.geometryFromEsriShape(geomref);
+ if (geom == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
if (GeometryUtils.getType(geomref) == GeometryUtils.OGCType.ST_POLYGON) {
- Method extMethod;
- try {
- // expect to streamline with updated geometry-api
- // OGCLineString extRing = ((OGCPolygon)(ogcGeometry)).exteriorRing();
- extMethod = OGCPolygon.class.getMethod("exteriorRing");
- } catch (Exception e) {
- LogUtils.Log_InternalError(LOG, "ST_ExteriorRing: " + e);
- try {
- extMethod = OGCPolygon.class.getMethod("exterorRing");
- } catch (Exception x) {
- LogUtils.Log_InternalError(LOG, "ST_ExteriorRing: " + x);
- return null;
- }
- }
try {
- OGCLineString extRing = (OGCLineString) (extMethod.invoke(ogcGeometry));
- return GeometryUtils.geometryToEsriShapeBytesWritable(extRing);
+ LinearRing ring = ((Polygon) geom).getExteriorRing();
+ // Return as LineString per OGC spec (not LinearRing which is JTS-specific)
+ Geometry lineString = geom.getFactory().createLineString(ring.getCoordinateSequence());
+ return GeometryUtils.geometryToEsriShapeBytesWritable(lineString);
} catch (Exception e) {
LogUtils.Log_InternalError(LOG, "ST_ExteriorRing: " + e);
return null;
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_GeodesicLengthWGS84.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_GeodesicLengthWGS84.java
index 0d351d00916d..4c87ea17656e 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_GeodesicLengthWGS84.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_GeodesicLengthWGS84.java
@@ -17,14 +17,13 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.Geometry;
-import com.esri.core.geometry.GeometryEngine;
-import com.esri.core.geometry.MultiPath;
-import com.esri.core.geometry.Point;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.serde2.io.DoubleWritable;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.CoordinateSequence;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.LineString;
+import org.locationtech.jts.geom.MultiLineString;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -66,37 +65,46 @@ public DoubleWritable evaluate(BytesWritable geomref) {
return null;
}
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geomref);
- if (ogcGeometry == null) {
+ Geometry geom = GeometryUtils.geometryFromEsriShape(geomref);
+ if (geom == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
- Geometry esriGeom = ogcGeometry.getEsriGeometry();
- switch (esriGeom.getType()) {
- case Point:
- case MultiPoint:
- resultDouble.set(0.);
- break;
- default:
- MultiPath lines = (MultiPath) (esriGeom);
- int nPath = lines.getPathCount();
- double length = 0.;
- for (int ix = 0; ix < nPath; ix++) {
- int curPt = lines.getPathStart(ix);
- int pastPt = lines.getPathEnd(ix);
- Point fromPt = lines.getPoint(curPt);
- Point toPt = null;
- for (int vx = curPt + 1; vx < pastPt; vx++) {
- toPt = lines.getPoint(vx);
- length += GeometryEngine.geodesicDistanceOnWGS84(fromPt, toPt);
- fromPt = toPt;
+ switch (geom.getGeometryType()) {
+ case "Point", "MultiPoint" -> resultDouble.set(0.0);
+ case "LineString", "LinearRing" -> resultDouble.set(lineStringLength((LineString) geom));
+ case "MultiLineString" -> {
+ MultiLineString mls = (MultiLineString) geom;
+ double total = 0.0;
+ for (int i = 0; i < mls.getNumGeometries(); i++) {
+ total += lineStringLength((LineString) mls.getGeometryN(i));
}
+ resultDouble.set(total);
}
- resultDouble.set(length);
- break;
+ default -> resultDouble.set(0.0);
}
return resultDouble;
}
+
+ /**
+ * Computes the geodesic length of a single LineString by summing Haversine
+ * distances between consecutive vertices. Iterates the CoordinateSequence
+ * directly to avoid per-vertex Point object allocation.
+ */
+ private static double lineStringLength(LineString line) {
+ CoordinateSequence seq = line.getCoordinateSequence();
+ int nPts = seq.size();
+ if (nPts < 2) {
+ return 0.0;
+ }
+ double length = 0.0;
+ for (int i = 1; i < nPts; i++) {
+ length += Haversine.distanceMeters(
+ seq.getX(i - 1), seq.getY(i - 1),
+ seq.getX(i), seq.getY(i));
+ }
+ return length;
+ }
}
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_GeomCollection.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_GeomCollection.java
index 7d5bea4b9970..f8971bcb056e 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_GeomCollection.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_GeomCollection.java
@@ -17,14 +17,11 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.Geometry;
-import com.esri.core.geometry.GeometryEngine;
-import com.esri.core.geometry.SpatialReference;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.io.BytesWritable;
import org.apache.hadoop.io.Text;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -66,13 +63,11 @@ public BytesWritable evaluate(Text wkwrap, int wkid) throws UDFArgumentException
String wkt = wkwrap.toString();
try {
- Geometry geomObj = GeometryEngine.geometryFromWkt(wkt, 0, Geometry.Type.Unknown);
- SpatialReference spatialReference = null; // Idea: OGCGeometry.setSpatialReference after .fromText
+ Geometry geom = GeometryUtils.wktReader().read(wkt);
if (wkid != GeometryUtils.WKID_UNKNOWN) {
- spatialReference = SpatialReference.create(wkid);
+ geom.setSRID(wkid);
}
- OGCGeometry ogcObj = OGCGeometry.createFromEsriGeometry(geomObj, spatialReference);
- return GeometryUtils.geometryToEsriShapeBytesWritable(ogcObj);
+ return GeometryUtils.geometryToEsriShapeBytesWritable(geom);
} catch (Exception e) { // IllegalArgumentException, GeometryException
LogUtils.Log_InvalidText(LOG, wkt);
return null;
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_GeomFromGeoJson.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_GeomFromGeoJson.java
index 24bd8fb7c51d..cb3e25a45e42 100644
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_GeomFromGeoJson.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_GeomFromGeoJson.java
@@ -17,7 +17,6 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.exec.UDFArgumentLengthException;
@@ -28,6 +27,7 @@
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector.Category;
import org.apache.hadoop.hive.serde2.objectinspector.PrimitiveObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.PrimitiveObjectInspector.PrimitiveCategory;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -59,8 +59,8 @@ public Object evaluate(DeferredObject[] arguments) throws HiveException {
}
try {
- OGCGeometry ogcGeom = OGCGeometry.fromGeoJson(json);
- return GeometryUtils.geometryToEsriShapeBytesWritable(ogcGeom);
+ Geometry geom = GeometryUtils.geoJsonReader().read(json);
+ return GeometryUtils.geometryToEsriShapeBytesWritable(geom);
} catch (Exception e) {
LogUtils.Log_InvalidText(LOG, json);
}
@@ -109,4 +109,8 @@ public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumen
return GeometryUtils.geometryTransportObjectInspector;
}
+ @Override
+ public void close() {
+ GeometryUtils.cleanup();
+ }
}
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_GeomFromJson.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_GeomFromJson.java
index 74f6a533bf3d..4ba6baccd799 100644
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_GeomFromJson.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_GeomFromJson.java
@@ -17,8 +17,6 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.ogc.OGCGeometry;
-import com.fasterxml.jackson.core.JsonFactory;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.exec.UDFArgumentLengthException;
@@ -30,13 +28,18 @@
import org.apache.hadoop.hive.serde2.objectinspector.PrimitiveObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.PrimitiveObjectInspector.PrimitiveCategory;
+import org.locationtech.jts.geom.Geometry;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
@Description(name = "ST_GeomFromJSON",
value = "_FUNC_(json) - construct an ST_Geometry from Esri JSON",
extended = "Example:\n" + " SELECT _FUNC_('{\"x\":0.0,\"y\":0.0}') FROM src LIMIT 1; -- constructs ST_Point\n")
public class ST_GeomFromJson extends GenericUDF {
- static final JsonFactory jsonFactory = new JsonFactory();
+ private static final Logger LOG = LoggerFactory.getLogger(ST_GeomFromJson.class);
+
ObjectInspector jsonOI;
@Override
@@ -55,10 +58,13 @@ public Object evaluate(DeferredObject[] arguments) throws HiveException {
}
try {
- OGCGeometry ogcGeom = OGCGeometry.fromJson(json);
- return GeometryUtils.geometryToEsriShapeBytesWritable(ogcGeom);
+ Geometry jtsGeom = EsriJsonConverter.esriJsonToGeometry(json);
+ if (jtsGeom == null) {
+ return null;
+ }
+ return GeometryUtils.geometryToEsriShapeBytesWritable(jtsGeom);
} catch (Exception e) {
-
+ LOG.error("Failed to parse Esri JSON", e);
}
return null;
@@ -105,4 +111,8 @@ public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumen
return GeometryUtils.geometryTransportObjectInspector;
}
+ @Override
+ public void close() {
+ GeometryUtils.cleanup();
+ }
}
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_GeomFromShape.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_GeomFromShape.java
index fa090a301b27..e58b97bd24d4 100644
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_GeomFromShape.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_GeomFromShape.java
@@ -17,15 +17,16 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.Geometry;
-import com.esri.core.geometry.GeometryEngine;
-import org.apache.hadoop.hive.ql.udf.esri.GeometryUtils.OGCType;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
@Description(name = "ST_GeomFromShape",
value = "_FUNC_(shape) - construct ST_Geometry from Esri shape representation of geometry\n",
extended = "Example:\n"
@@ -40,29 +41,14 @@ public BytesWritable evaluate(BytesWritable shape) throws UDFArgumentException {
public BytesWritable evaluate(BytesWritable shape, int wkid) throws UDFArgumentException {
try {
- Geometry geometry = GeometryEngine.geometryFromEsriShape(shape.getBytes(), Geometry.Type.Unknown);
- switch (geometry.getType()) {
- case Point:
- return GeometryUtils.geometryToEsriShapeBytesWritable(geometry, wkid, OGCType.ST_POINT);
-
- case MultiPoint:
- return GeometryUtils.geometryToEsriShapeBytesWritable(geometry, wkid, OGCType.ST_MULTIPOINT);
-
- case Line:
- return GeometryUtils.geometryToEsriShapeBytesWritable(geometry, wkid, OGCType.ST_LINESTRING);
-
- case Polyline:
- return GeometryUtils.geometryToEsriShapeBytesWritable(geometry, wkid, OGCType.ST_MULTILINESTRING);
-
- case Envelope:
- return GeometryUtils.geometryToEsriShapeBytesWritable(geometry, wkid, OGCType.ST_POLYGON);
-
- case Polygon:
- return GeometryUtils.geometryToEsriShapeBytesWritable(geometry, wkid, OGCType.ST_MULTIPOLYGON);
-
- default:
- return GeometryUtils.geometryToEsriShapeBytesWritable(geometry, wkid, OGCType.UNKNOWN);
+ ByteBuffer shapeBuffer = ByteBuffer.wrap(shape.getBytes(), 0, shape.getLength())
+ .order(ByteOrder.LITTLE_ENDIAN);
+ Geometry jtsGeom = EsriShapeConverter.fromEsriShape(shapeBuffer);
+ if (jtsGeom == null) {
+ return null;
}
+ jtsGeom.setSRID(wkid);
+ return GeometryUtils.geometryToEsriShapeBytesWritable(jtsGeom, wkid);
} catch (Exception e) {
LogUtils.Log_ExceptionThrown(LOG, "geom-from-shape", e);
return null;
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_GeomFromText.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_GeomFromText.java
index 6b2d1abdb32e..f1ba6d1f13f7 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_GeomFromText.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_GeomFromText.java
@@ -17,12 +17,11 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.SpatialReference;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.io.BytesWritable;
import org.apache.hadoop.io.Text;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -72,13 +71,11 @@ public BytesWritable evaluate(Text wkwrap, int wkid) throws UDFArgumentException
String wkt = wkwrap.toString();
try {
- SpatialReference spatialReference = null;
+ Geometry geom = GeometryUtils.wktReader().read(wkt);
if (wkid != GeometryUtils.WKID_UNKNOWN) {
- spatialReference = SpatialReference.create(wkid);
+ geom.setSRID(wkid);
}
- OGCGeometry ogcObj = OGCGeometry.fromText(wkt);
- ogcObj.setSpatialReference(spatialReference);
- return GeometryUtils.geometryToEsriShapeBytesWritable(ogcObj);
+ return GeometryUtils.geometryToEsriShapeBytesWritable(geom);
} catch (Exception e) { // IllegalArgumentException, GeometryException
LogUtils.Log_InvalidText(LOG, wkt);
return null;
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_GeomFromWKB.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_GeomFromWKB.java
index f9631c07fe78..1a9831c42794 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_GeomFromWKB.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_GeomFromWKB.java
@@ -17,15 +17,13 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.SpatialReference;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-
-import java.nio.ByteBuffer;
+import java.util.Arrays;
@Description(name = "ST_GeomFromWKB",
value = "_FUNC_(wkb) - construct an ST_Geometry from OGC well-known binary",
@@ -76,16 +74,12 @@ public BytesWritable evaluate(BytesWritable wkb) throws UDFArgumentException {
public BytesWritable evaluate(BytesWritable wkb, int wkid) throws UDFArgumentException {
try {
- SpatialReference spatialReference = null;
+ byte[] byteArr = Arrays.copyOf(wkb.getBytes(), wkb.getLength());
+ Geometry geom = GeometryUtils.wkbReader().read(byteArr);
if (wkid != GeometryUtils.WKID_UNKNOWN) {
- spatialReference = SpatialReference.create(wkid);
+ geom.setSRID(wkid);
}
- byte[] byteArr = wkb.getBytes();
- ByteBuffer byteBuf = ByteBuffer.allocate(byteArr.length);
- byteBuf.put(byteArr);
- OGCGeometry ogcObj = OGCGeometry.fromBinary(byteBuf);
- ogcObj.setSpatialReference(spatialReference);
- return GeometryUtils.geometryToEsriShapeBytesWritable(ogcObj);
+ return GeometryUtils.geometryToEsriShapeBytesWritable(geom);
} catch (Exception e) { // IllegalArgumentException, GeometryException
LOG.error(e.getMessage());
return null;
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_GeometryN.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_GeometryN.java
index 0c6c8c3154fa..bd54e673c11f 100644
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_GeometryN.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_GeometryN.java
@@ -17,13 +17,10 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.ogc.OGCGeometry;
-import com.esri.core.geometry.ogc.OGCMultiLineString;
-import com.esri.core.geometry.ogc.OGCMultiPoint;
-import com.esri.core.geometry.ogc.OGCMultiPolygon;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.io.BytesWritable;
import org.apache.hadoop.io.IntWritable;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -42,8 +39,8 @@ public BytesWritable evaluate(BytesWritable geomref, IntWritable index) {
return null;
}
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geomref);
- if (ogcGeometry == null) {
+ Geometry geom = GeometryUtils.geometryFromEsriShape(geomref);
+ if (geom == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
@@ -51,7 +48,6 @@ public BytesWritable evaluate(BytesWritable geomref, IntWritable index) {
int idx = index.get() - 1; // 1-based UI, 0-based engine
try {
GeometryUtils.OGCType ogcType = GeometryUtils.getType(geomref);
- OGCGeometry ogcGeom = null;
switch (ogcType) {
case ST_POINT:
LogUtils.Log_InvalidType(LOG, GeometryUtils.OGCType.ST_MULTIPOINT, ogcType);
@@ -62,17 +58,9 @@ public BytesWritable evaluate(BytesWritable geomref, IntWritable index) {
case ST_POLYGON:
LogUtils.Log_InvalidType(LOG, GeometryUtils.OGCType.ST_MULTIPOLYGON, ogcType);
return null;
- case ST_MULTIPOINT:
- ogcGeom = ((OGCMultiPoint) ogcGeometry).geometryN(idx);
- break;
- case ST_MULTILINESTRING:
- ogcGeom = ((OGCMultiLineString) ogcGeometry).geometryN(idx);
- break;
- case ST_MULTIPOLYGON:
- ogcGeom = ((OGCMultiPolygon) ogcGeometry).geometryN(idx);
- break;
+ default:
+ return GeometryUtils.geometryToEsriShapeBytesWritable(geom.getGeometryN(idx));
}
- return GeometryUtils.geometryToEsriShapeBytesWritable(ogcGeom);
} catch (Exception e) {
LogUtils.Log_InternalError(LOG, "ST_GeometryN: " + e);
return null;
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_GeometryRelational.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_GeometryRelational.java
index 0bc483552c68..eeafe95f1e6a 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_GeometryRelational.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_GeometryRelational.java
@@ -17,21 +17,19 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.Geometry.GeometryAccelerationDegree;
-import com.esri.core.geometry.OperatorContains;
-import com.esri.core.geometry.OperatorSimpleRelation;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDF;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.prep.PreparedGeometry;
+import org.locationtech.jts.geom.prep.PreparedGeometryFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Abstract class that all simple relational tests (contains, touches, ...) extend from
- *
*/
public abstract class ST_GeometryRelational extends GenericUDF {
private static final Logger LOG = LoggerFactory.getLogger(ST_GeometryRelational.class);
@@ -43,27 +41,27 @@ public abstract class ST_GeometryRelational extends GenericUDF {
private transient HiveGeometryOIHelper geomHelper1;
private transient HiveGeometryOIHelper geomHelper2;
- private transient OperatorSimpleRelation opSimpleRelation;
private transient boolean firstRun = true;
+ private PreparedGeometry preparedGeom1 = null;
- private transient boolean geom1IsAccelerated = false;
+ /**
+ * Execute the spatial relationship test between two geometries.
+ */
+ protected abstract boolean executeRelation(Geometry geom1, Geometry geom2);
/**
- * Operators that extend this should return an instance of
- * OperatorSimpleRelation
- *
- * @return operator for simple relationship tests
+ * Execute the spatial relationship test using a PreparedGeometry for the first argument.
+ * Subclasses can override this for optimized prepared geometry operations.
*/
- protected abstract OperatorSimpleRelation getRelationOperator();
+ protected boolean executeRelationPrepared(PreparedGeometry prepGeom1, Geometry geom2) {
+ return executeRelation(prepGeom1.getGeometry(), geom2);
+ }
@Override
public ObjectInspector initialize(ObjectInspector[] OIs) throws UDFArgumentException {
- opSimpleRelation = getRelationOperator();
-
if (OIs.length != NUM_ARGS) {
- throw new UDFArgumentException("The " + opSimpleRelation.getType().toString().toLowerCase()
- + " relationship operator takes exactly two arguments");
+ throw new UDFArgumentException("Spatial relationship operators take exactly two arguments");
}
geomHelper1 = HiveGeometryOIHelper.create(OIs[GEOM_1], GEOM_1);
@@ -75,7 +73,7 @@ public ObjectInspector initialize(ObjectInspector[] OIs) throws UDFArgumentExcep
}
firstRun = true;
- geom1IsAccelerated = false;
+ preparedGeom1 = null;
return PrimitiveObjectInspectorFactory.javaBooleanObjectInspector;
}
@@ -83,30 +81,27 @@ public ObjectInspector initialize(ObjectInspector[] OIs) throws UDFArgumentExcep
@Override
public Object evaluate(DeferredObject[] args) throws HiveException {
- OGCGeometry geom1 = geomHelper1.getGeometry(args);
- OGCGeometry geom2 = geomHelper2.getGeometry(args);
+ Geometry geom1 = geomHelper1.getGeometry(args);
+ Geometry geom2 = geomHelper2.getGeometry(args);
if (geom1 == null || geom2 == null) {
return false;
}
if (firstRun && geomHelper1.isConstant()) {
-
- // accelerate geometry 1 for quick relation operations since it is constant
- geom1IsAccelerated = opSimpleRelation.accelerateGeometry(geom1.getEsriGeometry(), geom1.getEsriSpatialReference(),
- GeometryAccelerationDegree.enumMedium);
+ preparedGeom1 = PreparedGeometryFactory.prepare(geom1);
}
firstRun = false;
- return opSimpleRelation
- .execute(geom1.getEsriGeometry(), geom2.getEsriGeometry(), geom1.getEsriSpatialReference(), null);
+ if (preparedGeom1 != null) {
+ return executeRelationPrepared(preparedGeom1, geom2);
+ }
+ return executeRelation(geom1, geom2);
}
@Override
public void close() {
- if (geom1IsAccelerated && geomHelper1 != null && geomHelper1.getConstantGeometry() != null) {
- OperatorContains.deaccelerateGeometry(geomHelper1.getConstantGeometry().getEsriGeometry());
- }
+ GeometryUtils.cleanup();
}
}
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_InteriorRingN.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_InteriorRingN.java
index c0e93f991c87..34ec0c55a913 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_InteriorRingN.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_InteriorRingN.java
@@ -17,12 +17,11 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.ogc.OGCGeometry;
-import com.esri.core.geometry.ogc.OGCLineString;
-import com.esri.core.geometry.ogc.OGCPolygon;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.io.BytesWritable;
import org.apache.hadoop.io.IntWritable;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.Polygon;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -52,8 +51,8 @@ public BytesWritable evaluate(BytesWritable geomref, IntWritable index) {
return null;
}
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geomref);
- if (ogcGeometry == null) {
+ Geometry geom = GeometryUtils.geometryFromEsriShape(geomref);
+ if (geom == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
@@ -61,8 +60,7 @@ public BytesWritable evaluate(BytesWritable geomref, IntWritable index) {
int idx = index.get() - 1; // 1-based UI, 0-based engine
if (GeometryUtils.getType(geomref) == GeometryUtils.OGCType.ST_POLYGON) {
try {
- OGCLineString hole = ((OGCPolygon) (ogcGeometry)).interiorRingN(idx);
- return GeometryUtils.geometryToEsriShapeBytesWritable(hole);
+ return GeometryUtils.geometryToEsriShapeBytesWritable(((Polygon) geom).getInteriorRingN(idx));
} catch (Exception e) {
LogUtils.Log_InternalError(LOG, "ST_InteriorRingN: " + e);
return null;
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Intersection.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Intersection.java
index f0d2eff1094b..c1c6a266f077 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Intersection.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Intersection.java
@@ -17,9 +17,9 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -47,16 +47,15 @@ public BytesWritable evaluate(BytesWritable geometryref1, BytesWritable geometry
return null;
}
- OGCGeometry ogcGeom1 = GeometryUtils.geometryFromEsriShape(geometryref1);
- OGCGeometry ogcGeom2 = GeometryUtils.geometryFromEsriShape(geometryref2);
- if (ogcGeom1 == null || ogcGeom2 == null) {
+ Geometry geom1 = GeometryUtils.geometryFromEsriShape(geometryref1);
+ Geometry geom2 = GeometryUtils.geometryFromEsriShape(geometryref2);
+ if (geom1 == null || geom2 == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
- OGCGeometry commonGeom;
try {
- commonGeom = ogcGeom1.intersection(ogcGeom2);
+ Geometry commonGeom = geom1.intersection(geom2);
return GeometryUtils.geometryToEsriShapeBytesWritable(commonGeom);
} catch (Exception e) {
LogUtils.Log_InternalError(LOG, "ST_Intersection: " + e);
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Intersects.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Intersects.java
index 0db3d30396f5..ec48b9f80236 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Intersects.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Intersects.java
@@ -17,9 +17,9 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.OperatorIntersects;
-import com.esri.core.geometry.OperatorSimpleRelation;
import org.apache.hadoop.hive.ql.exec.Description;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.prep.PreparedGeometry;
@Description(name = "ST_Intersects",
value = "_FUNC_(geometry1, geometry2) - return true if geometry1 intersects geometry2",
@@ -30,8 +30,13 @@
public class ST_Intersects extends ST_GeometryRelational {
@Override
- protected OperatorSimpleRelation getRelationOperator() {
- return OperatorIntersects.local();
+ protected boolean executeRelation(Geometry geom1, Geometry geom2) {
+ return geom1.intersects(geom2);
+ }
+
+ @Override
+ protected boolean executeRelationPrepared(PreparedGeometry prepGeom1, Geometry geom2) {
+ return prepGeom1.intersects(geom2);
}
@Override
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Is3D.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Is3D.java
index e879bc211c3e..4a115b5286ad 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Is3D.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Is3D.java
@@ -17,10 +17,11 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.io.BooleanWritable;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.io.Ordinate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -61,13 +62,13 @@ public BooleanWritable evaluate(BytesWritable geomref) {
return null;
}
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geomref);
- if (ogcGeometry == null) {
+ Geometry geom = GeometryUtils.geometryFromEsriShape(geomref);
+ if (geom == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
- resultBoolean.set(ogcGeometry.is3D());
+ resultBoolean.set(GeometryUtils.getOrdinates(geom).contains(Ordinate.Z));
return resultBoolean;
}
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_IsClosed.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_IsClosed.java
index 9f498b0b085e..a6f227ed39cf 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_IsClosed.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_IsClosed.java
@@ -17,12 +17,12 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.MultiPath;
-import com.esri.core.geometry.Point;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.io.BooleanWritable;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.LineString;
+import org.locationtech.jts.geom.MultiLineString;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -69,32 +69,29 @@ public BooleanWritable evaluate(BytesWritable geomref) {
return null;
}
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geomref);
- if (ogcGeometry == null) {
+ Geometry geom = GeometryUtils.geometryFromEsriShape(geomref);
+ if (geom == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
try {
-
switch (GeometryUtils.getType(geomref)) {
case ST_LINESTRING:
+ resultBoolean.set(((LineString) geom).isClosed());
+ return resultBoolean;
case ST_MULTILINESTRING:
- MultiPath lines = (MultiPath) (ogcGeometry.getEsriGeometry());
- int nPaths = lines.getPathCount();
- boolean rslt = true;
- for (int ix = 0; rslt && ix < nPaths; ix++) {
- Point p0 = lines.getPoint(lines.getPathStart(ix));
- Point pf = lines.getPoint(lines.getPathEnd(ix) - 1);
- rslt = rslt && pf.equals(p0); // no tolerance - OGC
+ MultiLineString mls = (MultiLineString) geom;
+ boolean closed = true;
+ for (int i = 0; closed && i < mls.getNumGeometries(); i++) {
+ closed = ((LineString) mls.getGeometryN(i)).isClosed();
}
- resultBoolean.set(rslt);
+ resultBoolean.set(closed);
return resultBoolean;
default: // ST_IsClosed gives ERROR on Point or Polygon, on Postgres/Oracle
LogUtils.Log_InvalidType(LOG, GeometryUtils.OGCType.ST_LINESTRING, GeometryUtils.getType(geomref));
return null;
}
-
} catch (Exception e) {
LogUtils.Log_InternalError(LOG, "ST_IsClosed" + e);
return null;
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_IsEmpty.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_IsEmpty.java
index 51cc8ae05258..3b107673666e 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_IsEmpty.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_IsEmpty.java
@@ -17,10 +17,10 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.io.BooleanWritable;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -59,14 +59,14 @@ public BooleanWritable evaluate(BytesWritable geomref) {
return null;
}
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geomref);
- if (ogcGeometry == null) {
+ Geometry geom = GeometryUtils.geometryFromEsriShape(geomref);
+ if (geom == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
try {
- resultBoolean.set(ogcGeometry.isEmpty());
+ resultBoolean.set(geom.isEmpty());
} catch (Exception e) {
LogUtils.Log_InternalError(LOG, "ST_IsEmpty" + e);
return null;
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_IsMeasured.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_IsMeasured.java
index 6fbd36f7bb90..27a5acfbba5d 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_IsMeasured.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_IsMeasured.java
@@ -17,10 +17,11 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.io.BooleanWritable;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.io.Ordinate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -61,13 +62,13 @@ public BooleanWritable evaluate(BytesWritable geomref) {
return null;
}
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geomref);
- if (ogcGeometry == null) {
+ Geometry geom = GeometryUtils.geometryFromEsriShape(geomref);
+ if (geom == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
- resultBoolean.set(ogcGeometry.isMeasured());
+ resultBoolean.set(GeometryUtils.getOrdinates(geom).contains(Ordinate.M));
return resultBoolean;
}
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_IsRing.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_IsRing.java
index d0361bb551d5..fcfadaa5114c 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_IsRing.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_IsRing.java
@@ -17,11 +17,11 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.ogc.OGCGeometry;
-import com.esri.core.geometry.ogc.OGCLineString;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.io.BooleanWritable;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.LineString;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -61,24 +61,22 @@ public BooleanWritable evaluate(BytesWritable geomref) {
return null;
}
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geomref);
- if (ogcGeometry == null) {
+ Geometry geom = GeometryUtils.geometryFromEsriShape(geomref);
+ if (geom == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
try {
-
switch (GeometryUtils.getType(geomref)) {
case ST_LINESTRING:
- OGCLineString lns = (OGCLineString) ogcGeometry;
- resultBoolean.set(lns.isClosed() && lns.isSimple());
+ LineString ls = (LineString) geom;
+ resultBoolean.set(ls.isClosed() && ls.isSimple());
return resultBoolean;
default: // ST_IsRing gives ERROR on Point, Polygon, or MultiLineString - on Postgres
LogUtils.Log_InvalidType(LOG, GeometryUtils.OGCType.ST_LINESTRING, GeometryUtils.getType(geomref));
return null;
}
-
} catch (Exception e) {
LogUtils.Log_InternalError(LOG, "ST_IsRing" + e);
return null;
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_IsSimple.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_IsSimple.java
index c7de9af59748..9265b5ae5794 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_IsSimple.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_IsSimple.java
@@ -17,10 +17,10 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.io.BooleanWritable;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -63,15 +63,15 @@ public BooleanWritable evaluate(BytesWritable geomref) {
return null;
}
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geomref);
+ Geometry geom = GeometryUtils.geometryFromEsriShape(geomref);
- if (ogcGeometry == null) {
+ if (geom == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
try {
- resultBoolean.set(ogcGeometry.isSimple());
+ resultBoolean.set(geom.isSimple());
} catch (Exception e) {
LogUtils.Log_InternalError(LOG, "ST_IsSimple" + e);
return null;
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Length.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Length.java
index 3a79855e9be0..6ce9a3717080 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Length.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Length.java
@@ -17,10 +17,10 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.serde2.io.DoubleWritable;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -54,13 +54,13 @@ public DoubleWritable evaluate(BytesWritable geomref) {
return null;
}
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geomref);
- if (ogcGeometry == null) {
+ Geometry geom = GeometryUtils.geometryFromEsriShape(geomref);
+ if (geom == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
- resultDouble.set(ogcGeometry.getEsriGeometry().calculateLength2D());
+ resultDouble.set(geom.getLength());
return resultDouble;
}
}
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_LineFromWKB.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_LineFromWKB.java
index 2b19736b4a07..391a36f5713e 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_LineFromWKB.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_LineFromWKB.java
@@ -17,15 +17,13 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.SpatialReference;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-
-import java.nio.ByteBuffer;
+import java.util.Arrays;
@Description(name = "ST_LineFromWKB",
value = "_FUNC_(wkb) - construct an ST_LineString from OGC well-known binary",
@@ -55,17 +53,11 @@ public BytesWritable evaluate(BytesWritable wkb) throws UDFArgumentException {
public BytesWritable evaluate(BytesWritable wkb, int wkid) throws UDFArgumentException {
try {
- SpatialReference spatialReference = null;
- if (wkid != GeometryUtils.WKID_UNKNOWN) {
- spatialReference = SpatialReference.create(wkid);
- }
- byte[] byteArr = wkb.getBytes();
- ByteBuffer byteBuf = ByteBuffer.allocate(byteArr.length);
- byteBuf.put(byteArr);
- OGCGeometry ogcObj = OGCGeometry.fromBinary(byteBuf);
- ogcObj.setSpatialReference(spatialReference);
- if (ogcObj.geometryType().equals("LineString")) {
- return GeometryUtils.geometryToEsriShapeBytesWritable(ogcObj);
+ byte[] bytes = Arrays.copyOf(wkb.getBytes(), wkb.getLength());
+ Geometry geom = GeometryUtils.wkbReader().read(bytes);
+ if (geom.getGeometryType().equals("LineString")) {
+ geom.setSRID(wkid);
+ return GeometryUtils.geometryToEsriShapeBytesWritable(geom, wkid);
} else {
LogUtils.Log_InvalidType(LOG, GeometryUtils.OGCType.ST_LINESTRING, GeometryUtils.OGCType.UNKNOWN);
return null;
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_LineString.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_LineString.java
index a50c93e9b996..b9ffd61e18f1 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_LineString.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_LineString.java
@@ -17,14 +17,14 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.Point;
-import com.esri.core.geometry.Polyline;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.serde2.io.DoubleWritable;
import org.apache.hadoop.io.BytesWritable;
import org.apache.hadoop.io.Text;
+import org.locationtech.jts.geom.Coordinate;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.Point;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -61,14 +61,12 @@ public BytesWritable evaluate(DoubleWritable... xyPairs) throws UDFArgumentExcep
}
try {
- Polyline linestring = new Polyline();
- linestring.startPath(xyPairs[0].get(), xyPairs[1].get());
-
- for (int i = 2; i < xyPairs.length; i += 2) {
- linestring.lineTo(xyPairs[i].get(), xyPairs[i + 1].get());
+ Coordinate[] coords = new Coordinate[xyPairs.length / 2];
+ for (int i = 0; i < xyPairs.length; i += 2) {
+ coords[i / 2] = new Coordinate(xyPairs[i].get(), xyPairs[i + 1].get());
}
-
- return GeometryUtils.geometryToEsriShapeBytesWritable(OGCGeometry.createFromEsriGeometry(linestring, null));
+ Geometry linestring = GeometryUtils.GEOMETRY_FACTORY.createLineString(coords);
+ return GeometryUtils.geometryToEsriShapeBytesWritable(linestring);
} catch (Exception e) {
LogUtils.Log_InternalError(LOG, "ST_LineString: " + e);
return null;
@@ -83,21 +81,16 @@ public BytesWritable evaluate(ArrayList xs, ArrayList points) throws UDFArgumen
}
try {
- Polyline linestring = new Polyline();
-
+ Coordinate[] coords = new Coordinate[points.size()];
for (int ix = 0; ix < points.size(); ++ix) {
BytesWritable geomref = points.get(ix);
- OGCGeometry gcur = GeometryUtils.geometryFromEsriShape(geomref);
+ Geometry gcur = GeometryUtils.geometryFromEsriShape(geomref);
if (gcur == null || GeometryUtils.getType(geomref) != GeometryUtils.OGCType.ST_POINT) {
if (gcur == null)
LogUtils.Log_ArgumentsNull(LOG);
@@ -123,14 +115,11 @@ public BytesWritable evaluate(ArrayList points) throws UDFArgumen
LogUtils.Log_InvalidType(LOG, GeometryUtils.OGCType.ST_POINT, GeometryUtils.getType(geomref));
return null;
}
- if (ix == 0) {
- linestring.startPath((Point) gcur.getEsriGeometry());
- } else {
- linestring.lineTo((Point) gcur.getEsriGeometry());
- }
+ Point pt = (Point) gcur;
+ coords[ix] = pt.getCoordinate();
}
-
- return GeometryUtils.geometryToEsriShapeBytesWritable(OGCGeometry.createFromEsriGeometry(linestring, null));
+ Geometry linestring = GeometryUtils.GEOMETRY_FACTORY.createLineString(coords);
+ return GeometryUtils.geometryToEsriShapeBytesWritable(linestring);
} catch (Exception e) {
LogUtils.Log_InternalError(LOG, "ST_LineString: " + e);
return null;
@@ -141,10 +130,9 @@ public BytesWritable evaluate(ArrayList points) throws UDFArgumen
public BytesWritable evaluate(Text wkwrap) throws UDFArgumentException {
String wkt = wkwrap.toString();
try {
- OGCGeometry ogcObj = OGCGeometry.fromText(wkt);
- ogcObj.setSpatialReference(null);
- if (ogcObj.geometryType().equals("LineString")) {
- return GeometryUtils.geometryToEsriShapeBytesWritable(ogcObj);
+ Geometry geom = GeometryUtils.wktReader().read(wkt);
+ if (geom.getGeometryType().equals("LineString")) {
+ return GeometryUtils.geometryToEsriShapeBytesWritable(geom);
} else {
LogUtils.Log_InvalidType(LOG, GeometryUtils.OGCType.ST_LINESTRING, GeometryUtils.OGCType.UNKNOWN);
return null;
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_M.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_M.java
index ef176e937b0a..54fe8cca0bf4 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_M.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_M.java
@@ -17,11 +17,12 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.ogc.OGCGeometry;
-import com.esri.core.geometry.ogc.OGCPoint;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.serde2.io.DoubleWritable;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Coordinate;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.Point;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -59,19 +60,20 @@ public DoubleWritable evaluate(BytesWritable geomref) {
return null;
}
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geomref);
- if (ogcGeometry == null) {
- return null;
- }
- if (!ogcGeometry.isMeasured()) {
- LogUtils.Log_NotMeasured(LOG);
+ Geometry geom = GeometryUtils.geometryFromEsriShape(geomref);
+ if (geom == null) {
return null;
}
switch (GeometryUtils.getType(geomref)) {
case ST_POINT:
- OGCPoint pt = (OGCPoint) ogcGeometry;
- resultDouble.set(pt.M());
+ Coordinate coord = ((Point) geom).getCoordinate();
+ double m = coord.getM();
+ if (Double.isNaN(m)) {
+ LogUtils.Log_NotMeasured(LOG);
+ return null;
+ }
+ resultDouble.set(m);
return resultDouble;
default:
LogUtils.Log_InvalidType(LOG, GeometryUtils.OGCType.ST_POINT, GeometryUtils.getType(geomref));
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MLineFromWKB.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MLineFromWKB.java
index 01e5cd70d02a..f9922c31168f 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MLineFromWKB.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MLineFromWKB.java
@@ -17,15 +17,13 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.SpatialReference;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-
-import java.nio.ByteBuffer;
+import java.util.Arrays;
@Description(name = "ST_MLineFromWKB",
value = "_FUNC_(wkb) - construct an ST_MultiLineString from OGC well-known binary",
@@ -55,18 +53,12 @@ public BytesWritable evaluate(BytesWritable wkb) throws UDFArgumentException {
public BytesWritable evaluate(BytesWritable wkb, int wkid) throws UDFArgumentException {
try {
- SpatialReference spatialReference = null;
- if (wkid != GeometryUtils.WKID_UNKNOWN) {
- spatialReference = SpatialReference.create(wkid);
- }
- byte[] byteArr = wkb.getBytes();
- ByteBuffer byteBuf = ByteBuffer.allocate(byteArr.length);
- byteBuf.put(byteArr);
- OGCGeometry ogcObj = OGCGeometry.fromBinary(byteBuf);
- ogcObj.setSpatialReference(spatialReference);
- String gType = ogcObj.geometryType();
+ byte[] bytes = Arrays.copyOf(wkb.getBytes(), wkb.getLength());
+ Geometry geom = GeometryUtils.wkbReader().read(bytes);
+ String gType = geom.getGeometryType();
if (gType.equals("MultiLineString") || gType.equals("LineString")) {
- return GeometryUtils.geometryToEsriShapeBytesWritable(ogcObj);
+ geom.setSRID(wkid);
+ return GeometryUtils.geometryToEsriShapeBytesWritable(geom, wkid);
} else {
LogUtils.Log_InvalidType(LOG, GeometryUtils.OGCType.ST_MULTILINESTRING, GeometryUtils.OGCType.UNKNOWN);
return null;
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MPointFromWKB.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MPointFromWKB.java
index 2fe92022bb35..b4de15bcb345 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MPointFromWKB.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MPointFromWKB.java
@@ -17,15 +17,13 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.SpatialReference;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-
-import java.nio.ByteBuffer;
+import java.util.Arrays;
@Description(name = "ST_MPointFromWKB",
value = "_FUNC_(wkb) - construct an ST_MultiPoint from OGC well-known binary",
@@ -55,20 +53,14 @@ public BytesWritable evaluate(BytesWritable wkb) throws UDFArgumentException {
public BytesWritable evaluate(BytesWritable wkb, int wkid) throws UDFArgumentException {
try {
- SpatialReference spatialReference = null;
- if (wkid != GeometryUtils.WKID_UNKNOWN) {
- spatialReference = SpatialReference.create(wkid);
- }
- byte[] byteArr = wkb.getBytes();
- ByteBuffer byteBuf = ByteBuffer.allocate(byteArr.length);
- byteBuf.put(byteArr);
- OGCGeometry ogcObj = OGCGeometry.fromBinary(byteBuf);
- ogcObj.setSpatialReference(spatialReference);
- String gType = ogcObj.geometryType();
+ byte[] bytes = Arrays.copyOf(wkb.getBytes(), wkb.getLength());
+ Geometry geom = GeometryUtils.wkbReader().read(bytes);
+ String gType = geom.getGeometryType();
if (gType.equals("MultiPoint") || gType.equals("Point")) {
- return GeometryUtils.geometryToEsriShapeBytesWritable(ogcObj);
+ geom.setSRID(wkid);
+ return GeometryUtils.geometryToEsriShapeBytesWritable(geom, wkid);
} else {
- LogUtils.Log_InvalidType(LOG, GeometryUtils.OGCType.ST_LINESTRING, GeometryUtils.OGCType.UNKNOWN);
+ LogUtils.Log_InvalidType(LOG, GeometryUtils.OGCType.ST_MULTIPOINT, GeometryUtils.OGCType.UNKNOWN);
return null;
}
} catch (Exception e) { // IllegalArgumentException, GeometryException
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MPolyFromWKB.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MPolyFromWKB.java
index 1092226df060..3c00ecbdc9b2 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MPolyFromWKB.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MPolyFromWKB.java
@@ -17,15 +17,13 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.SpatialReference;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-
-import java.nio.ByteBuffer;
+import java.util.Arrays;
@Description(name = "ST_MPolyFromWKB",
value = "_FUNC_(wkb) - construct an ST_MultiPolygon from OGC well-known binary",
@@ -55,18 +53,12 @@ public BytesWritable evaluate(BytesWritable wkb) throws UDFArgumentException {
public BytesWritable evaluate(BytesWritable wkb, int wkid) throws UDFArgumentException {
try {
- SpatialReference spatialReference = null;
- if (wkid != GeometryUtils.WKID_UNKNOWN) {
- spatialReference = SpatialReference.create(wkid);
- }
- byte[] byteArr = wkb.getBytes();
- ByteBuffer byteBuf = ByteBuffer.allocate(byteArr.length);
- byteBuf.put(byteArr);
- OGCGeometry ogcObj = OGCGeometry.fromBinary(byteBuf);
- ogcObj.setSpatialReference(spatialReference);
- String gType = ogcObj.geometryType();
+ byte[] bytes = Arrays.copyOf(wkb.getBytes(), wkb.getLength());
+ Geometry geom = GeometryUtils.wkbReader().read(bytes);
+ String gType = geom.getGeometryType();
if (gType.equals("MultiPolygon") || gType.equals("Polygon")) {
- return GeometryUtils.geometryToEsriShapeBytesWritable(ogcObj);
+ geom.setSRID(wkid);
+ return GeometryUtils.geometryToEsriShapeBytesWritable(geom, wkid);
} else {
LogUtils.Log_InvalidType(LOG, GeometryUtils.OGCType.ST_MULTIPOLYGON, GeometryUtils.OGCType.UNKNOWN);
return null;
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MaxM.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MaxM.java
index 1964ca43723a..2dfdaa74f05f 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MaxM.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MaxM.java
@@ -17,10 +17,11 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.serde2.io.DoubleWritable;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.CoordinateFilter;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -63,17 +64,26 @@ public DoubleWritable evaluate(BytesWritable geomref) {
return null;
}
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geomref);
- if (ogcGeometry == null) {
+ Geometry geom = GeometryUtils.geometryFromEsriShape(geomref);
+ if (geom == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
- if (!ogcGeometry.isMeasured()) {
+
+ double[] max = {Double.NaN};
+ geom.apply((CoordinateFilter) coord -> {
+ double m = coord.getM();
+ if (!Double.isNaN(m)) {
+ max[0] = Double.isNaN(max[0]) ? m : Math.max(max[0], m);
+ }
+ });
+
+ if (Double.isNaN(max[0])) {
LogUtils.Log_NotMeasured(LOG);
return null;
}
- resultDouble.set(ogcGeometry.MaxMeasure());
+ resultDouble.set(max[0]);
return resultDouble;
}
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MaxX.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MaxX.java
index e1000c2c8f48..973893d733ff 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MaxX.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MaxX.java
@@ -17,11 +17,10 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.Envelope;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.serde2.io.DoubleWritable;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -72,15 +71,17 @@ public DoubleWritable evaluate(BytesWritable geomref) {
return null;
}
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geomref);
- if (ogcGeometry == null) {
+ Geometry geom = GeometryUtils.geometryFromEsriShape(geomref);
+ if (geom == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
- Envelope envBound = new Envelope();
- ogcGeometry.getEsriGeometry().queryEnvelope(envBound);
- resultDouble.set(envBound.getXMax());
+ if (geom.isEmpty()) {
+ resultDouble.set(Double.NaN);
+ } else {
+ resultDouble.set(geom.getEnvelopeInternal().getMaxX());
+ }
return resultDouble;
}
}
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MaxY.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MaxY.java
index 3ffb17e30349..b832d5293a49 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MaxY.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MaxY.java
@@ -17,11 +17,10 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.Envelope;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.serde2.io.DoubleWritable;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -72,15 +71,17 @@ public DoubleWritable evaluate(BytesWritable geomref) {
return null;
}
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geomref);
- if (ogcGeometry == null) {
+ Geometry geom = GeometryUtils.geometryFromEsriShape(geomref);
+ if (geom == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
- Envelope envBound = new Envelope();
- ogcGeometry.getEsriGeometry().queryEnvelope(envBound);
- resultDouble.set(envBound.getYMax());
+ if (geom.isEmpty()) {
+ resultDouble.set(Double.NaN);
+ } else {
+ resultDouble.set(geom.getEnvelopeInternal().getMaxY());
+ }
return resultDouble;
}
}
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MaxZ.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MaxZ.java
index c1f526ce9b35..9901f77a4081 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MaxZ.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MaxZ.java
@@ -17,10 +17,11 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.serde2.io.DoubleWritable;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.CoordinateFilter;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -63,17 +64,26 @@ public DoubleWritable evaluate(BytesWritable geomref) {
return null;
}
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geomref);
- if (ogcGeometry == null) {
+ Geometry geom = GeometryUtils.geometryFromEsriShape(geomref);
+ if (geom == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
- if (!ogcGeometry.is3D()) {
+
+ double[] max = {Double.NaN};
+ geom.apply((CoordinateFilter) coord -> {
+ double z = coord.getZ();
+ if (!Double.isNaN(z)) {
+ max[0] = Double.isNaN(max[0]) ? z : Math.max(max[0], z);
+ }
+ });
+
+ if (Double.isNaN(max[0])) {
LogUtils.Log_Not3D(LOG);
return null;
}
- resultDouble.set(ogcGeometry.MaxZ());
+ resultDouble.set(max[0]);
return resultDouble;
}
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MinM.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MinM.java
index a202754bfba8..94f2a2673d52 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MinM.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MinM.java
@@ -17,10 +17,11 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.serde2.io.DoubleWritable;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.CoordinateFilter;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -63,17 +64,26 @@ public DoubleWritable evaluate(BytesWritable geomref) {
return null;
}
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geomref);
- if (ogcGeometry == null) {
+ Geometry geom = GeometryUtils.geometryFromEsriShape(geomref);
+ if (geom == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
- if (!ogcGeometry.isMeasured()) {
+
+ double[] min = {Double.NaN};
+ geom.apply((CoordinateFilter) coord -> {
+ double m = coord.getM();
+ if (!Double.isNaN(m)) {
+ min[0] = Double.isNaN(min[0]) ? m : Math.min(min[0], m);
+ }
+ });
+
+ if (Double.isNaN(min[0])) {
LogUtils.Log_NotMeasured(LOG);
return null;
}
- resultDouble.set(ogcGeometry.MinMeasure());
+ resultDouble.set(min[0]);
return resultDouble;
}
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MinX.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MinX.java
index 10d86a77b642..b34b4df56920 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MinX.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MinX.java
@@ -17,11 +17,10 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.Envelope;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.serde2.io.DoubleWritable;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -72,15 +71,17 @@ public DoubleWritable evaluate(BytesWritable geomref) {
return null;
}
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geomref);
- if (ogcGeometry == null) {
+ Geometry geom = GeometryUtils.geometryFromEsriShape(geomref);
+ if (geom == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
- Envelope envBound = new Envelope();
- ogcGeometry.getEsriGeometry().queryEnvelope(envBound);
- resultDouble.set(envBound.getXMin());
+ if (geom.isEmpty()) {
+ resultDouble.set(Double.NaN);
+ } else {
+ resultDouble.set(geom.getEnvelopeInternal().getMinX());
+ }
return resultDouble;
}
}
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MinY.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MinY.java
index ea90923f50fb..2abedd07beb5 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MinY.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MinY.java
@@ -17,11 +17,10 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.Envelope;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.serde2.io.DoubleWritable;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -72,15 +71,17 @@ public DoubleWritable evaluate(BytesWritable geomref) {
return null;
}
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geomref);
- if (ogcGeometry == null) {
+ Geometry geom = GeometryUtils.geometryFromEsriShape(geomref);
+ if (geom == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
- Envelope envBound = new Envelope();
- ogcGeometry.getEsriGeometry().queryEnvelope(envBound);
- resultDouble.set(envBound.getYMin());
+ if (geom.isEmpty()) {
+ resultDouble.set(Double.NaN);
+ } else {
+ resultDouble.set(geom.getEnvelopeInternal().getMinY());
+ }
return resultDouble;
}
}
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MinZ.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MinZ.java
index 5fbebc4a7cb3..6b3dfec9c5c3 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MinZ.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MinZ.java
@@ -17,10 +17,11 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.serde2.io.DoubleWritable;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.CoordinateFilter;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -63,17 +64,26 @@ public DoubleWritable evaluate(BytesWritable geomref) {
return null;
}
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geomref);
- if (ogcGeometry == null) {
+ Geometry geom = GeometryUtils.geometryFromEsriShape(geomref);
+ if (geom == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
- if (!ogcGeometry.is3D()) {
+
+ double[] min = {Double.NaN};
+ geom.apply((CoordinateFilter) coord -> {
+ double z = coord.getZ();
+ if (!Double.isNaN(z)) {
+ min[0] = Double.isNaN(min[0]) ? z : Math.min(min[0], z);
+ }
+ });
+
+ if (Double.isNaN(min[0])) {
LogUtils.Log_Not3D(LOG);
return null;
}
- resultDouble.set(ogcGeometry.MinZ());
+ resultDouble.set(min[0]);
return resultDouble;
}
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MultiLineString.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MultiLineString.java
index 0fc4ddcab6e2..9839b85cdad8 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MultiLineString.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MultiLineString.java
@@ -17,14 +17,15 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.Polyline;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.exec.UDFArgumentLengthException;
import org.apache.hadoop.hive.serde2.io.DoubleWritable;
import org.apache.hadoop.io.BytesWritable;
import org.apache.hadoop.io.Text;
+import org.locationtech.jts.geom.Coordinate;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.LineString;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -61,24 +62,25 @@ public BytesWritable evaluate(List... multipaths) throws UDFArgu
}
try {
- Polyline mPolyline = new Polyline();
-
+ LineString[] lineStrings = new LineString[multipaths.length];
int arg_idx = 0;
+
for (List multipath : multipaths) {
if (multipath.size() % 2 != 0) {
LogUtils.Log_VariableArgumentLengthXY(LOG, arg_idx);
return null;
}
- mPolyline.startPath(multipath.get(0).get(), multipath.get(1).get());
-
- for (int i = 2; i < multipath.size(); i += 2) {
- mPolyline.lineTo(multipath.get(i).get(), multipath.get(i + 1).get());
+ Coordinate[] coords = new Coordinate[multipath.size() / 2];
+ for (int i = 0; i < multipath.size(); i += 2) {
+ coords[i / 2] = new Coordinate(multipath.get(i).get(), multipath.get(i + 1).get());
}
+ lineStrings[arg_idx] = GeometryUtils.GEOMETRY_FACTORY.createLineString(coords);
arg_idx++;
}
- return GeometryUtils.geometryToEsriShapeBytesWritable(OGCGeometry.createFromEsriGeometry(mPolyline, null, true));
+ Geometry mLineString = GeometryUtils.GEOMETRY_FACTORY.createMultiLineString(lineStrings);
+ return GeometryUtils.geometryToEsriShapeBytesWritable(mLineString);
} catch (Exception e) {
LogUtils.Log_InternalError(LOG, "ST_MultiLineString: " + e);
return null;
@@ -89,10 +91,9 @@ public BytesWritable evaluate(List... multipaths) throws UDFArgu
public BytesWritable evaluate(Text wkwrap) throws UDFArgumentException {
String wkt = wkwrap.toString();
try {
- OGCGeometry ogcObj = OGCGeometry.fromText(wkt);
- ogcObj.setSpatialReference(null);
- if (ogcObj.geometryType().equals("MultiLineString")) {
- return GeometryUtils.geometryToEsriShapeBytesWritable(ogcObj);
+ Geometry geom = GeometryUtils.wktReader().read(wkt);
+ if (geom.getGeometryType().equals("MultiLineString")) {
+ return GeometryUtils.geometryToEsriShapeBytesWritable(geom);
} else {
LogUtils.Log_InvalidType(LOG, GeometryUtils.OGCType.ST_MULTILINESTRING, GeometryUtils.OGCType.UNKNOWN);
return null;
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MultiPoint.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MultiPoint.java
index 3ede57503776..779013efd305 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MultiPoint.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MultiPoint.java
@@ -17,14 +17,14 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.MultiPoint;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.exec.UDFArgumentLengthException;
import org.apache.hadoop.hive.serde2.io.DoubleWritable;
import org.apache.hadoop.io.BytesWritable;
import org.apache.hadoop.io.Text;
+import org.locationtech.jts.geom.Coordinate;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -34,7 +34,7 @@
extended = "Example:\n" + " SELECT _FUNC_(1, 1, 2, 2, 3, 3) from src LIMIT 1; -- multipoint with 3 points\n"
+ " SELECT _FUNC_('MULTIPOINT ((10 40), (40 30))') from src LIMIT 1; -- multipoint of 2 points")
//@HivePdkUnitTests(
-// cases = {
+// cases = {
// @HivePdkUnitTest(
// query = "select st_asjson(st_multipoint(1, 1, 2, 2, 3, 3)) from onerow",
// result = "{\"points\":[[1.0,1.0],[2.0,2.0],[3.0,3.0]]}"
@@ -63,13 +63,12 @@ public BytesWritable evaluate(DoubleWritable... xyPairs) throws UDFArgumentLengt
}
try {
- MultiPoint mPoint = new MultiPoint();
-
+ Coordinate[] coords = new Coordinate[xyPairs.length / 2];
for (int i = 0; i < xyPairs.length; i += 2) {
- mPoint.add(xyPairs[i].get(), xyPairs[i + 1].get());
+ coords[i / 2] = new Coordinate(xyPairs[i].get(), xyPairs[i + 1].get());
}
-
- return GeometryUtils.geometryToEsriShapeBytesWritable(OGCGeometry.createFromEsriGeometry(mPoint, null, true));
+ Geometry mPoint = GeometryUtils.GEOMETRY_FACTORY.createMultiPointFromCoords(coords);
+ return GeometryUtils.geometryToEsriShapeBytesWritable(mPoint);
} catch (Exception e) {
LogUtils.Log_InternalError(LOG, "ST_MultiPoint: " + e);
return null;
@@ -80,10 +79,9 @@ public BytesWritable evaluate(DoubleWritable... xyPairs) throws UDFArgumentLengt
public BytesWritable evaluate(Text wkwrap) throws UDFArgumentException {
String wkt = wkwrap.toString();
try {
- OGCGeometry ogcObj = OGCGeometry.fromText(wkt);
- ogcObj.setSpatialReference(null);
- if (ogcObj.geometryType().equals("MultiPoint")) {
- return GeometryUtils.geometryToEsriShapeBytesWritable(ogcObj);
+ Geometry geom = GeometryUtils.wktReader().read(wkt);
+ if (geom.getGeometryType().equals("MultiPoint")) {
+ return GeometryUtils.geometryToEsriShapeBytesWritable(geom);
} else {
LogUtils.Log_InvalidType(LOG, GeometryUtils.OGCType.ST_MULTIPOINT, GeometryUtils.OGCType.UNKNOWN);
return null;
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MultiPolygon.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MultiPolygon.java
index 8f981a3c4024..406697f96b62 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MultiPolygon.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_MultiPolygon.java
@@ -17,13 +17,13 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.exec.UDFArgumentLengthException;
import org.apache.hadoop.hive.serde2.io.DoubleWritable;
import org.apache.hadoop.io.BytesWritable;
import org.apache.hadoop.io.Text;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -37,7 +37,7 @@
+ " SELECT _FUNC_(array(1, 1, 1, 2, 2, 2, 2, 1), array(3, 3, 3, 4, 4, 4, 4, 3)) from src LIMIT 1;\n"
+ " SELECT _FUNC_('multipolygon (((0 0, 0 1, 1 0, 0 0)), ((2 2, 2 3, 3 2, 2 2)))') from src LIMIT 1;")
//@HivePdkUnitTests(
-// cases = {
+// cases = {
// @HivePdkUnitTest(
// query = "select st_asjson(st_multipolygon(array(1, 1, 1, 2, 2, 2, 2, 1), array(3, 3, 3, 4, 4, 4, 4, 3))) from onerow;",
// result = "{\"rings\":[[[1.0,1.0],[1.0,2.0],[2.0,2.0],[2.0,1.0],[1.0,1.0]],[[3.0,3.0],[3.0,4.0],[4.0,4.0],[4.0,3.0],[3.0,3.0]]]}"
@@ -101,10 +101,9 @@ public BytesWritable evaluate(List... multipaths) throws UDFArgu
public BytesWritable evaluate(Text wkwrap) throws UDFArgumentException {
String wkt = wkwrap.toString();
try {
- OGCGeometry ogcObj = OGCGeometry.fromText(wkt);
- ogcObj.setSpatialReference(null);
- if (ogcObj.geometryType().equals("MultiPolygon")) {
- return GeometryUtils.geometryToEsriShapeBytesWritable(ogcObj);
+ Geometry geom = GeometryUtils.wktReader().read(wkt);
+ if (geom.getGeometryType().equals("MultiPolygon")) {
+ return GeometryUtils.geometryToEsriShapeBytesWritable(geom);
} else {
LogUtils.Log_InvalidType(LOG, GeometryUtils.OGCType.ST_MULTIPOLYGON, GeometryUtils.OGCType.UNKNOWN);
return null;
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_NumGeometries.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_NumGeometries.java
index cfca1b5294ac..4d1bfdadf845 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_NumGeometries.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_NumGeometries.java
@@ -17,13 +17,10 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.ogc.OGCGeometry;
-import com.esri.core.geometry.ogc.OGCMultiLineString;
-import com.esri.core.geometry.ogc.OGCMultiPoint;
-import com.esri.core.geometry.ogc.OGCMultiPolygon;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.io.BytesWritable;
import org.apache.hadoop.io.IntWritable;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -43,8 +40,8 @@ public IntWritable evaluate(BytesWritable geomref) {
return null;
}
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geomref);
- if (ogcGeometry == null) {
+ Geometry geom = GeometryUtils.geometryFromEsriShape(geomref);
+ if (geom == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
@@ -61,18 +58,10 @@ public IntWritable evaluate(BytesWritable geomref) {
case ST_POLYGON:
LogUtils.Log_InvalidType(LOG, GeometryUtils.OGCType.ST_MULTIPOLYGON, ogcType);
return null;
- case ST_MULTIPOINT:
- resultInt.set(((OGCMultiPoint) ogcGeometry).numGeometries());
- break;
- case ST_MULTILINESTRING:
- resultInt.set(((OGCMultiLineString) ogcGeometry).numGeometries());
- break;
- case ST_MULTIPOLYGON:
- resultInt.set(((OGCMultiPolygon) ogcGeometry).numGeometries());
+ default:
+ resultInt.set(geom.getNumGeometries());
break;
}
- } catch (ClassCastException cce) { // single vs Multi geometry type
- resultInt.set(1);
} catch (Exception e) {
LogUtils.Log_InternalError(LOG, "ST_NumGeometries: " + e);
return null;
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_NumInteriorRing.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_NumInteriorRing.java
index 01fb8264ceab..419022d4815a 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_NumInteriorRing.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_NumInteriorRing.java
@@ -17,11 +17,11 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.ogc.OGCGeometry;
-import com.esri.core.geometry.ogc.OGCPolygon;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.io.BytesWritable;
import org.apache.hadoop.io.IntWritable;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.Polygon;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -57,14 +57,14 @@ public IntWritable evaluate(BytesWritable geomref) {
return null;
}
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geomref);
- if (ogcGeometry == null) {
+ Geometry geom = GeometryUtils.geometryFromEsriShape(geomref);
+ if (geom == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
if (GeometryUtils.getType(geomref) == GeometryUtils.OGCType.ST_POLYGON) {
try {
- resultInt.set(((OGCPolygon) (ogcGeometry)).numInteriorRing());
+ resultInt.set(((Polygon) geom).getNumInteriorRing());
return resultInt;
} catch (Exception e) {
LogUtils.Log_InternalError(LOG, "ST_NumInteriorRing: " + e);
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_NumPoints.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_NumPoints.java
index 2ec95c090cb3..c1f8f0bced54 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_NumPoints.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_NumPoints.java
@@ -17,14 +17,10 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.Geometry;
-import com.esri.core.geometry.MultiPath;
-import com.esri.core.geometry.MultiPoint;
-import com.esri.core.geometry.Polygon;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.io.BytesWritable;
import org.apache.hadoop.io.IntWritable;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -72,28 +68,13 @@ public IntWritable evaluate(BytesWritable geomref) {
return null;
}
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geomref);
- if (ogcGeometry == null) {
+ Geometry geom = GeometryUtils.geometryFromEsriShape(geomref);
+ if (geom == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
- Geometry esriGeom = ogcGeometry.getEsriGeometry();
- switch (esriGeom.getType()) {
- case Point:
- resultInt.set(esriGeom.isEmpty() ? 0 : 1);
- break;
- case MultiPoint:
- resultInt.set(((MultiPoint) (esriGeom)).getPointCount());
- break;
- case Polygon:
- Polygon polygon = (Polygon) (esriGeom);
- resultInt.set(polygon.getPointCount() + polygon.getPathCount());
- break;
- default:
- resultInt.set(((MultiPath) (esriGeom)).getPointCount());
- break;
- }
+ resultInt.set(geom.getNumPoints());
return resultInt;
}
}
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Overlaps.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Overlaps.java
index 0810f0cd595c..e2ce0f104a17 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Overlaps.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Overlaps.java
@@ -17,9 +17,9 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.OperatorOverlaps;
-import com.esri.core.geometry.OperatorSimpleRelation;
import org.apache.hadoop.hive.ql.exec.Description;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.prep.PreparedGeometry;
@Description(name = "ST_Overlaps",
value = "_FUNC_(geometry1, geometry2) - return true if geometry1 overlaps geometry2",
@@ -30,8 +30,13 @@
public class ST_Overlaps extends ST_GeometryRelational {
@Override
- protected OperatorSimpleRelation getRelationOperator() {
- return OperatorOverlaps.local();
+ protected boolean executeRelation(Geometry geom1, Geometry geom2) {
+ return geom1.overlaps(geom2);
+ }
+
+ @Override
+ protected boolean executeRelationPrepared(PreparedGeometry prepGeom1, Geometry geom2) {
+ return prepGeom1.overlaps(geom2);
}
@Override
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Point.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Point.java
index 75969e38eca3..90073e49da3b 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Point.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Point.java
@@ -17,13 +17,15 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.Point;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.serde2.io.DoubleWritable;
import org.apache.hadoop.io.BytesWritable;
import org.apache.hadoop.io.Text;
+import org.locationtech.jts.geom.Coordinate;
+import org.locationtech.jts.geom.CoordinateXYM;
+import org.locationtech.jts.geom.CoordinateXYZM;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -64,14 +66,18 @@ public BytesWritable evaluate(DoubleWritable x, DoubleWritable y, DoubleWritable
return null;
}
try {
- Point stPt = new Point(x.get(), y.get());
- if (z != null)
- stPt.setZ(z.get());
- if (m != null)
- stPt.setM(m.get());
- BytesWritable ret =
- GeometryUtils.geometryToEsriShapeBytesWritable(OGCGeometry.createFromEsriGeometry(stPt, null));
- return ret;
+ Coordinate coord;
+ if (m != null && z != null) {
+ coord = new CoordinateXYZM(x.get(), y.get(), z.get(), m.get());
+ } else if (z != null) {
+ coord = new Coordinate(x.get(), y.get(), z.get());
+ } else if (m != null) {
+ coord = new CoordinateXYM(x.get(), y.get(), m.get());
+ } else {
+ coord = new Coordinate(x.get(), y.get());
+ }
+ Geometry stPt = GeometryUtils.GEOMETRY_FACTORY.createPoint(coord);
+ return GeometryUtils.geometryToEsriShapeBytesWritable(stPt);
} catch (Exception e) {
//LogUtils.Log_InternalError(LOG, "ST_Point: " + e);
return null;
@@ -82,10 +88,9 @@ public BytesWritable evaluate(DoubleWritable x, DoubleWritable y, DoubleWritable
public BytesWritable evaluate(Text wkwrap) throws UDFArgumentException {
String wkt = wkwrap.toString();
try {
- OGCGeometry ogcObj = OGCGeometry.fromText(wkt);
- ogcObj.setSpatialReference(null);
- if (ogcObj.geometryType().equals("Point")) {
- return GeometryUtils.geometryToEsriShapeBytesWritable(ogcObj);
+ Geometry geom = GeometryUtils.wktReader().read(wkt);
+ if (geom.getGeometryType().equals("Point")) {
+ return GeometryUtils.geometryToEsriShapeBytesWritable(geom);
} else {
LogUtils.Log_InvalidType(LOG, GeometryUtils.OGCType.ST_POINT, GeometryUtils.OGCType.UNKNOWN);
return null;
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_PointFromWKB.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_PointFromWKB.java
index 5bd428d0cbcd..cd41d4dcafff 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_PointFromWKB.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_PointFromWKB.java
@@ -17,15 +17,13 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.SpatialReference;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-
-import java.nio.ByteBuffer;
+import java.util.Arrays;
@Description(name = "ST_PointFromWKB",
value = "_FUNC_(wkb) - construct an ST_Point from OGC well-known binary",
@@ -55,17 +53,11 @@ public BytesWritable evaluate(BytesWritable wkb) throws UDFArgumentException {
public BytesWritable evaluate(BytesWritable wkb, int wkid) throws UDFArgumentException {
try {
- SpatialReference spatialReference = null;
- if (wkid != GeometryUtils.WKID_UNKNOWN) {
- spatialReference = SpatialReference.create(wkid);
- }
- byte[] byteArr = wkb.getBytes();
- ByteBuffer byteBuf = ByteBuffer.allocate(byteArr.length);
- byteBuf.put(byteArr);
- OGCGeometry ogcObj = OGCGeometry.fromBinary(byteBuf);
- ogcObj.setSpatialReference(spatialReference);
- if (ogcObj.geometryType().equals("Point")) {
- return GeometryUtils.geometryToEsriShapeBytesWritable(ogcObj);
+ byte[] bytes = Arrays.copyOf(wkb.getBytes(), wkb.getLength());
+ Geometry geom = GeometryUtils.wkbReader().read(bytes);
+ if (geom.getGeometryType().equals("Point")) {
+ geom.setSRID(wkid);
+ return GeometryUtils.geometryToEsriShapeBytesWritable(geom, wkid);
} else {
LogUtils.Log_InvalidType(LOG, GeometryUtils.OGCType.ST_POINT, GeometryUtils.OGCType.UNKNOWN);
return null;
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_PointN.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_PointN.java
index 7300fab3cde1..194da51d087e 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_PointN.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_PointN.java
@@ -17,14 +17,13 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.Geometry;
-import com.esri.core.geometry.MultiPath;
-import com.esri.core.geometry.MultiPoint;
-import com.esri.core.geometry.Point;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.io.BytesWritable;
import org.apache.hadoop.io.IntWritable;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.LineString;
+import org.locationtech.jts.geom.MultiPoint;
+import org.locationtech.jts.geom.Point;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -66,33 +65,32 @@ public BytesWritable evaluate(BytesWritable geomref, IntWritable index) {
return null;
}
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geomref);
- if (ogcGeometry == null) {
+ Geometry geom = GeometryUtils.geometryFromEsriShape(geomref);
+ if (geom == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
- Geometry esriGeom = ogcGeometry.getEsriGeometry();
- Point pn = null;
int idx = index.get();
idx = (idx == 0) ? 0 : idx - 1; // consistency with SDE ST_Geometry
- switch (esriGeom.getType()) {
- case Line:
- case Polyline:
- MultiPath lines = (MultiPath) (esriGeom);
+
+ Point pn = null;
+ switch (GeometryUtils.getType(geomref)) {
+ case ST_LINESTRING:
+ LineString ls = (LineString) geom;
try {
- pn = lines.getPoint(idx);
+ pn = ls.getPointN(idx);
} catch (Exception e) {
- LogUtils.Log_InvalidIndex(LOG, idx + 1, 1, lines.getPointCount());
+ LogUtils.Log_InvalidIndex(LOG, idx + 1, 1, ls.getNumPoints());
return null;
}
break;
- case MultiPoint:
- MultiPoint mp = (MultiPoint) (esriGeom);
+ case ST_MULTIPOINT:
+ MultiPoint mp = (MultiPoint) geom;
try {
- pn = mp.getPoint(idx);
+ pn = (Point) mp.getGeometryN(idx);
} catch (Exception e) {
- LogUtils.Log_InvalidIndex(LOG, idx + 1, 1, mp.getPointCount());
+ LogUtils.Log_InvalidIndex(LOG, idx + 1, 1, mp.getNumGeometries());
return null;
}
break;
@@ -100,7 +98,6 @@ public BytesWritable evaluate(BytesWritable geomref, IntWritable index) {
LogUtils.Log_InvalidType(LOG, GeometryUtils.OGCType.ST_LINESTRING, GeometryUtils.getType(geomref));
return null;
}
- return GeometryUtils
- .geometryToEsriShapeBytesWritable(pn, GeometryUtils.getWKID(geomref), GeometryUtils.OGCType.ST_POINT);
+ return GeometryUtils.geometryToEsriShapeBytesWritable(pn);
}
}
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_PointZ.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_PointZ.java
index 5018a2609ab5..67c27bb7d201 100644
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_PointZ.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_PointZ.java
@@ -17,11 +17,12 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.Point;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.serde2.io.DoubleWritable;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Coordinate;
+import org.locationtech.jts.geom.CoordinateXYZM;
+import org.locationtech.jts.geom.Geometry;
@Description(name = "ST_PointZ",
value = "_FUNC_(x, y, z) - constructor for 3D point",
@@ -37,9 +38,13 @@ public BytesWritable evaluate(DoubleWritable x, DoubleWritable y, DoubleWritable
if (x == null || y == null || z == null) {
return null;
}
- Point stPt = new Point(x.get(), y.get(), z.get());
- if (m != null)
- stPt.setM(m.get());
- return GeometryUtils.geometryToEsriShapeBytesWritable(OGCGeometry.createFromEsriGeometry(stPt, null));
+ Coordinate coord;
+ if (m != null) {
+ coord = new CoordinateXYZM(x.get(), y.get(), z.get(), m.get());
+ } else {
+ coord = new Coordinate(x.get(), y.get(), z.get());
+ }
+ Geometry stPt = GeometryUtils.GEOMETRY_FACTORY.createPoint(coord);
+ return GeometryUtils.geometryToEsriShapeBytesWritable(stPt);
}
}
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_PolyFromWKB.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_PolyFromWKB.java
index 6c9f4ef68ff6..75083b47cb3d 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_PolyFromWKB.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_PolyFromWKB.java
@@ -17,15 +17,13 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.SpatialReference;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-
-import java.nio.ByteBuffer;
+import java.util.Arrays;
@Description(name = "ST_PolyFromWKB",
value = "_FUNC_(wkb) - construct an ST_Polygon from OGC well-known binary",
@@ -55,17 +53,11 @@ public BytesWritable evaluate(BytesWritable wkb) throws UDFArgumentException {
public BytesWritable evaluate(BytesWritable wkb, int wkid) throws UDFArgumentException {
try {
- SpatialReference spatialReference = null;
- if (wkid != GeometryUtils.WKID_UNKNOWN) {
- spatialReference = SpatialReference.create(wkid);
- }
- byte[] byteArr = wkb.getBytes();
- ByteBuffer byteBuf = ByteBuffer.allocate(byteArr.length);
- byteBuf.put(byteArr);
- OGCGeometry ogcObj = OGCGeometry.fromBinary(byteBuf);
- ogcObj.setSpatialReference(spatialReference);
- if (ogcObj.geometryType().equals("Polygon")) {
- return GeometryUtils.geometryToEsriShapeBytesWritable(ogcObj);
+ byte[] bytes = Arrays.copyOf(wkb.getBytes(), wkb.getLength());
+ Geometry geom = GeometryUtils.wkbReader().read(bytes);
+ if (geom.getGeometryType().equals("Polygon")) {
+ geom.setSRID(wkid);
+ return GeometryUtils.geometryToEsriShapeBytesWritable(geom, wkid);
} else {
LogUtils.Log_InvalidType(LOG, GeometryUtils.OGCType.ST_POLYGON, GeometryUtils.OGCType.UNKNOWN);
return null;
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Polygon.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Polygon.java
index 8cf407e3176b..3ac7eedee1f6 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Polygon.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Polygon.java
@@ -17,13 +17,13 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.exec.UDFArgumentLengthException;
import org.apache.hadoop.hive.serde2.io.DoubleWritable;
import org.apache.hadoop.io.BytesWritable;
import org.apache.hadoop.io.Text;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -87,10 +87,9 @@ public BytesWritable evaluate(DoubleWritable... xyPairs) throws UDFArgumentLengt
public BytesWritable evaluate(Text wkwrap) throws UDFArgumentException {
String wkt = wkwrap.toString();
try {
- OGCGeometry ogcObj = OGCGeometry.fromText(wkt);
- ogcObj.setSpatialReference(null);
- if (ogcObj.geometryType().equals("Polygon")) {
- return GeometryUtils.geometryToEsriShapeBytesWritable(ogcObj);
+ Geometry geom = GeometryUtils.wktReader().read(wkt);
+ if (geom.getGeometryType().equals("Polygon")) {
+ return GeometryUtils.geometryToEsriShapeBytesWritable(geom);
} else {
LogUtils.Log_InvalidType(LOG, GeometryUtils.OGCType.ST_POLYGON, GeometryUtils.OGCType.UNKNOWN);
return null;
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Relate.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Relate.java
index 0c2ac0d1a6a2..0d7030025e83 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Relate.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Relate.java
@@ -17,10 +17,10 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.io.BooleanWritable;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -48,15 +48,15 @@ public BooleanWritable evaluate(BytesWritable geometryref1, BytesWritable geomet
return null;
}
- OGCGeometry ogcGeom1 = GeometryUtils.geometryFromEsriShape(geometryref1);
- OGCGeometry ogcGeom2 = GeometryUtils.geometryFromEsriShape(geometryref2);
- if (ogcGeom1 == null || ogcGeom2 == null) {
+ Geometry geom1 = GeometryUtils.geometryFromEsriShape(geometryref1);
+ Geometry geom2 = GeometryUtils.geometryFromEsriShape(geometryref2);
+ if (geom1 == null || geom2 == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
try {
- resultBoolean.set(ogcGeom1.relate(ogcGeom2, relation));
+ resultBoolean.set(geom1.relate(geom2, relation));
return resultBoolean;
} catch (Exception e) {
LogUtils.Log_InternalError(LOG, "ST_Relate: " + e);
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_StartPoint.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_StartPoint.java
index 8d876dfb2cd8..6c6f94fd6cc5 100644
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_StartPoint.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_StartPoint.java
@@ -17,11 +17,10 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.MultiPath;
-import com.esri.core.geometry.SpatialReference;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.LineString;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -44,21 +43,14 @@ public BytesWritable evaluate(BytesWritable geomref) {
return null;
}
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geomref);
- if (ogcGeometry == null) {
+ Geometry geom = GeometryUtils.geometryFromEsriShape(geomref);
+ if (geom == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
if (GeometryUtils.getType(geomref) == GeometryUtils.OGCType.ST_LINESTRING) {
- MultiPath lines = (MultiPath) (ogcGeometry.getEsriGeometry());
- int wkid = GeometryUtils.getWKID(geomref);
- SpatialReference spatialReference = null;
- if (wkid != GeometryUtils.WKID_UNKNOWN) {
- spatialReference = SpatialReference.create(wkid);
- }
- return GeometryUtils
- .geometryToEsriShapeBytesWritable(OGCGeometry.createFromEsriGeometry(lines.getPoint(0), spatialReference));
+ return GeometryUtils.geometryToEsriShapeBytesWritable(((LineString) geom).getStartPoint());
} else {
LogUtils.Log_InvalidType(LOG, GeometryUtils.OGCType.ST_LINESTRING, GeometryUtils.getType(geomref));
return null;
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_SymmetricDiff.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_SymmetricDiff.java
index 3d72b5180fd8..b3cbc19b6386 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_SymmetricDiff.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_SymmetricDiff.java
@@ -17,9 +17,9 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -63,15 +63,15 @@ public BytesWritable evaluate(BytesWritable geometryref1, BytesWritable geometry
return null;
}
- OGCGeometry ogcGeom1 = GeometryUtils.geometryFromEsriShape(geometryref1);
- OGCGeometry ogcGeom2 = GeometryUtils.geometryFromEsriShape(geometryref2);
- if (ogcGeom1 == null || ogcGeom2 == null) {
+ Geometry geom1 = GeometryUtils.geometryFromEsriShape(geometryref1);
+ Geometry geom2 = GeometryUtils.geometryFromEsriShape(geometryref2);
+ if (geom1 == null || geom2 == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
try {
- OGCGeometry diffGeometry = ogcGeom1.symDifference(ogcGeom2);
+ Geometry diffGeometry = geom1.symDifference(geom2);
return GeometryUtils.geometryToEsriShapeBytesWritable(diffGeometry);
} catch (Exception e) {
LogUtils.Log_InternalError(LOG, "ST_SymmetricDiff: " + e);
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Touches.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Touches.java
index 7881c48430dd..3783ea855028 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Touches.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Touches.java
@@ -17,9 +17,9 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.OperatorSimpleRelation;
-import com.esri.core.geometry.OperatorTouches;
import org.apache.hadoop.hive.ql.exec.Description;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.prep.PreparedGeometry;
@Description(name = "ST_Touches",
value = "_FUNC_(geometry1, geometry2) - return true if geometry1 touches geometry2",
@@ -30,8 +30,13 @@
public class ST_Touches extends ST_GeometryRelational {
@Override
- protected OperatorSimpleRelation getRelationOperator() {
- return OperatorTouches.local();
+ protected boolean executeRelation(Geometry geom1, Geometry geom2) {
+ return geom1.touches(geom2);
+ }
+
+ @Override
+ protected boolean executeRelationPrepared(PreparedGeometry prepGeom1, Geometry geom2) {
+ return prepGeom1.touches(geom2);
}
@Override
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Union.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Union.java
index 847881884408..0eaa554858e7 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Union.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Union.java
@@ -17,16 +17,16 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.Geometry;
-import com.esri.core.geometry.GeometryEngine;
-import com.esri.core.geometry.SpatialReference;
-import com.esri.core.geometry.ogc.OGCGeometry;
-import org.apache.hadoop.hive.ql.udf.esri.GeometryUtils.OGCType;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.operation.union.UnaryUnionOp;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.ArrayList;
+import java.util.List;
+
@Description(name = "ST_Union",
value = "_FUNC_(ST_Geometry, ST_Geometry, ...) - returns an ST_Geometry as the union of the supplied ST_Geometries",
extended =
@@ -59,8 +59,6 @@ public BytesWritable evaluate(BytesWritable... geomrefs) {
int firstWKID = 0;
- SpatialReference spatialRef = null;
-
// validate spatial references and geometries first
for (int i = 0; i < geomrefs.length; i++) {
@@ -73,44 +71,34 @@ public BytesWritable evaluate(BytesWritable... geomrefs) {
if (i == 0) {
firstWKID = GeometryUtils.getWKID(geomref);
- if (firstWKID != GeometryUtils.WKID_UNKNOWN) {
- spatialRef = SpatialReference.create(firstWKID);
- }
} else if (firstWKID != GeometryUtils.getWKID(geomref)) {
LogUtils.Log_SRIDMismatch(LOG, geomrefs[0], geomref);
return null;
}
}
- // now build geometry array to pass to GeometryEngine.union
- Geometry[] geomsToUnion = new Geometry[geomrefs.length];
+ // build geometry list to pass to UnaryUnionOp
+ List geomsToUnion = new ArrayList<>(geomrefs.length);
for (int i = 0; i < geomrefs.length; i++) {
- //HiveGeometry hiveGeometry = GeometryUtils.geometryFromEsriShape(geomrefs[i]);
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geomrefs[i]);
+ Geometry geom = GeometryUtils.geometryFromEsriShape(geomrefs[i]);
- // if (i==0){ // get from ogcGeometry rather than re-create above?
- // spatialRef = hiveGeometry.spatialReference;
- // }
-
- if (ogcGeometry == null) {
+ if (geom == null) {
LogUtils.Log_ArgumentsNull(LOG);
return null;
}
- geomsToUnion[i] = ogcGeometry.getEsriGeometry();
+ geomsToUnion.add(geom);
}
try {
- Geometry unioned = GeometryEngine.union(geomsToUnion, spatialRef);
+ Geometry unioned = UnaryUnionOp.union(geomsToUnion);
- // we have to infer the type of the differenced geometry because we don't know
+ // we have to infer the type of the unioned geometry because we don't know
// if it's going to end up as a single or multi-part geometry
- OGCType inferredType = GeometryUtils.getInferredOGCType(unioned);
-
- return GeometryUtils.geometryToEsriShapeBytesWritable(unioned, firstWKID, inferredType);
+ return GeometryUtils.geometryToEsriShapeBytesWritable(unioned, firstWKID);
} catch (Exception e) {
- LogUtils.Log_ExceptionThrown(LOG, "GeometryEngine.union", e);
+ LogUtils.Log_ExceptionThrown(LOG, "ST_Union", e);
return null;
}
}
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Within.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Within.java
index 8544f8fd69a5..49f04335fd0c 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Within.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Within.java
@@ -17,9 +17,9 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.OperatorSimpleRelation;
-import com.esri.core.geometry.OperatorWithin;
import org.apache.hadoop.hive.ql.exec.Description;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.prep.PreparedGeometry;
@Description(name = "ST_Within",
value = "_FUNC_(geometry1, geometry2) - return true if geometry1 is within geometry2",
@@ -30,8 +30,13 @@
public class ST_Within extends ST_GeometryRelational {
@Override
- protected OperatorSimpleRelation getRelationOperator() {
- return OperatorWithin.local();
+ protected boolean executeRelation(Geometry geom1, Geometry geom2) {
+ return geom1.within(geom2);
+ }
+
+ @Override
+ protected boolean executeRelationPrepared(PreparedGeometry prepGeom1, Geometry geom2) {
+ return prepGeom1.within(geom2);
}
@Override
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_X.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_X.java
index d3a75208c81a..ddf425971fab 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_X.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_X.java
@@ -17,11 +17,11 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.ogc.OGCGeometry;
-import com.esri.core.geometry.ogc.OGCPoint;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.serde2.io.DoubleWritable;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.Point;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -55,15 +55,14 @@ public DoubleWritable evaluate(BytesWritable geomref) {
return null;
}
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geomref);
- if (ogcGeometry == null) {
+ Geometry geom = GeometryUtils.geometryFromEsriShape(geomref);
+ if (geom == null) {
return null;
}
switch (GeometryUtils.getType(geomref)) {
case ST_POINT:
- OGCPoint pt = (OGCPoint) ogcGeometry;
- resultDouble.set(pt.X());
+ resultDouble.set(((Point) geom).getX());
return resultDouble;
default:
LogUtils.Log_InvalidType(LOG, GeometryUtils.OGCType.ST_POINT, GeometryUtils.getType(geomref));
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Y.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Y.java
index e748557e5dc5..2ceddfe7b374 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Y.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Y.java
@@ -17,11 +17,11 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.ogc.OGCGeometry;
-import com.esri.core.geometry.ogc.OGCPoint;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.serde2.io.DoubleWritable;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.Point;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -55,15 +55,14 @@ public DoubleWritable evaluate(BytesWritable geomref) {
return null;
}
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geomref);
- if (ogcGeometry == null) {
+ Geometry geom = GeometryUtils.geometryFromEsriShape(geomref);
+ if (geom == null) {
return null;
}
switch (GeometryUtils.getType(geomref)) {
case ST_POINT:
- OGCPoint pt = (OGCPoint) ogcGeometry;
- resultDouble.set(pt.Y());
+ resultDouble.set(((Point) geom).getY());
return resultDouble;
default:
LogUtils.Log_InvalidType(LOG, GeometryUtils.OGCType.ST_POINT, GeometryUtils.getType(geomref));
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Z.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Z.java
index 58a6252a4800..3dfcb111f854 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Z.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/ST_Z.java
@@ -17,11 +17,11 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.ogc.OGCGeometry;
-import com.esri.core.geometry.ogc.OGCPoint;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.serde2.io.DoubleWritable;
import org.apache.hadoop.io.BytesWritable;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.Point;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -63,19 +63,19 @@ public DoubleWritable evaluate(BytesWritable geomref) {
return null;
}
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geomref);
- if (ogcGeometry == null) {
- return null;
- }
- if (!ogcGeometry.is3D()) {
- LogUtils.Log_Not3D(LOG);
+ Geometry geom = GeometryUtils.geometryFromEsriShape(geomref);
+ if (geom == null) {
return null;
}
switch (GeometryUtils.getType(geomref)) {
case ST_POINT:
- OGCPoint pt = (OGCPoint) ogcGeometry;
- resultDouble.set(pt.Z());
+ double z = ((Point) geom).getCoordinate().getZ();
+ if (Double.isNaN(z)) {
+ LogUtils.Log_Not3D(LOG);
+ return null;
+ }
+ resultDouble.set(z);
return resultDouble;
default:
LogUtils.Log_InvalidType(LOG, GeometryUtils.OGCType.ST_POINT, GeometryUtils.getType(geomref));
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/serde/BaseJsonSerDe.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/serde/BaseJsonSerDe.java
index 76df357d4bef..b0390921bef3 100644
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/serde/BaseJsonSerDe.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/serde/BaseJsonSerDe.java
@@ -17,9 +17,9 @@
*/
package org.apache.hadoop.hive.ql.udf.esri.serde;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.udf.esri.GeometryUtils;
import org.apache.hadoop.hive.ql.udf.esri.shims.HiveShims;
+import org.locationtech.jts.geom.Geometry;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.JsonGenerator;
@@ -171,8 +171,8 @@ public Object deserialize(Writable json_in) throws SerDeException {
if ("geometry".equals(parser.getCurrentName())) {
if (geometryColumn > -1) {
// create geometry and insert into geometry field
- OGCGeometry ogcGeom = parseGeom(parser);
- row.set(geometryColumn, ogcGeom == null ? null : GeometryUtils.geometryToEsriShapeBytesWritable(ogcGeom));
+ Geometry geom = parseGeom(parser);
+ row.set(geometryColumn, geom == null ? null : GeometryUtils.geometryToEsriShapeBytesWritable(geom));
} else {
// no geometry in select field set, don't even bother parsing
parser.skipChildren();
@@ -275,8 +275,8 @@ public Writable serialize(Object obj, ObjectInspector oi) throws SerDeException
bytesWritable = (BytesWritable) got;
else // SparkSQL, #97
bytesWritable = new BytesWritable((byte[]) got); // idea: avoid extra object
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(bytesWritable);
- jsonGen.writeRaw(",\"geometry\":" + outGeom(ogcGeometry));
+ Geometry geometry = GeometryUtils.geometryFromEsriShape(bytesWritable);
+ jsonGen.writeRaw(",\"geometry\":" + outGeom(geometry));
}
}
@@ -335,11 +335,11 @@ private void generateJsonFromWritable(Writable value, int fieldIndex, String lab
}
}
- // Write OGCGeometry to JSON
- abstract protected String outGeom(OGCGeometry geom);
+ // Write JTS Geometry to JSON string
+ abstract protected String outGeom(Geometry geom);
- // Parse OGCGeometry from JSON
- abstract protected OGCGeometry parseGeom(JsonParser parser);
+ // Parse JTS Geometry from JSON
+ abstract protected Geometry parseGeom(JsonParser parser);
private java.sql.Date parseDate(JsonParser parser) throws IOException {
java.sql.Date jsd = null;
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/serde/EsriJsonSerDe.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/serde/EsriJsonSerDe.java
index afa692d93ccb..3426c24a6c60 100644
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/serde/EsriJsonSerDe.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/serde/EsriJsonSerDe.java
@@ -17,147 +17,35 @@
*/
package org.apache.hadoop.hive.ql.udf.esri.serde;
-import com.esri.core.geometry.Geometry;
-import com.esri.core.geometry.JsonGeometryException;
-import com.esri.core.geometry.JsonReader;
-import com.esri.core.geometry.MapGeometry;
-import com.esri.core.geometry.OperatorImportFromJson;
-import com.esri.core.geometry.ogc.OGCGeometry;
-import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.hadoop.hive.ql.udf.esri.EsriJsonConverter;
+import org.locationtech.jts.geom.Geometry;
public class EsriJsonSerDe extends BaseJsonSerDe {
@Override
- protected String outGeom(OGCGeometry geom) {
- return geom.asJson();
- }
-
- @Override
- protected OGCGeometry parseGeom(JsonParser parser) {
- MapGeometry mapGeom =
- OperatorImportFromJson.local().execute(Geometry.Type.Unknown, new HiveJsonParserReader(parser));
- return OGCGeometry.createFromEsriGeometry(mapGeom.getGeometry(), mapGeom.getSpatialReference());
- }
-}
-
-class HiveJsonParserReader implements JsonReader {
- private JsonParser m_jsonParser;
-
- public HiveJsonParserReader(JsonParser jsonParser) {
- this.m_jsonParser = jsonParser;
- }
-
- public static JsonReader createFromString(String str) {
+ protected String outGeom(Geometry geom) {
try {
- JsonFactory factory = new JsonFactory();
- JsonParser jsonParser = factory.createParser(str);
- jsonParser.nextToken();
- return new com.esri.core.geometry.JsonParserReader(jsonParser);
- } catch (Exception var3) {
- throw new JsonGeometryException(var3.getMessage());
+ int wkid = geom.getSRID();
+ return EsriJsonConverter.geometryToEsriJson(geom, wkid);
+ } catch (Exception e) {
+ return "null";
}
}
- public static JsonReader createFromStringNNT(String str) {
- try {
- JsonFactory factory = new JsonFactory();
- JsonParser jsonParser = factory.createParser(str);
- return new com.esri.core.geometry.JsonParserReader(jsonParser);
- } catch (Exception var3) {
- throw new JsonGeometryException(var3.getMessage());
- }
- }
-
- private static Token mapToken(JsonToken token) {
- if (token == JsonToken.END_ARRAY) {
- return Token.END_ARRAY;
- } else if (token == JsonToken.END_OBJECT) {
- return Token.END_OBJECT;
- } else if (token == JsonToken.FIELD_NAME) {
- return Token.FIELD_NAME;
- } else if (token == JsonToken.START_ARRAY) {
- return Token.START_ARRAY;
- } else if (token == JsonToken.START_OBJECT) {
- return Token.START_OBJECT;
- } else if (token == JsonToken.VALUE_FALSE) {
- return Token.VALUE_FALSE;
- } else if (token == JsonToken.VALUE_NULL) {
- return Token.VALUE_NULL;
- } else if (token == JsonToken.VALUE_NUMBER_FLOAT) {
- return Token.VALUE_NUMBER_FLOAT;
- } else if (token == JsonToken.VALUE_NUMBER_INT) {
- return Token.VALUE_NUMBER_INT;
- } else if (token == JsonToken.VALUE_STRING) {
- return Token.VALUE_STRING;
- } else if (token == JsonToken.VALUE_TRUE) {
- return Token.VALUE_TRUE;
- } else if (token == null) {
+ @Override
+ protected Geometry parseGeom(JsonParser parser) {
+ try {
+ ObjectMapper mapper = new ObjectMapper();
+ JsonNode node = mapper.readTree(parser);
+ if (node == null) {
+ return null;
+ }
+ return EsriJsonConverter.esriJsonToGeometry(node.toString());
+ } catch (Exception e) {
return null;
- } else {
- throw new JsonGeometryException("unexpected token");
- }
- }
-
- public Token nextToken() throws JsonGeometryException {
- try {
- JsonToken token = this.m_jsonParser.nextToken();
- return mapToken(token);
- } catch (Exception var2) {
- throw new JsonGeometryException(var2);
- }
- }
-
- public Token currentToken() throws JsonGeometryException {
- try {
- return mapToken(this.m_jsonParser.getCurrentToken());
- } catch (Exception var2) {
- throw new JsonGeometryException(var2);
- }
- }
-
- public void skipChildren() throws JsonGeometryException {
- try {
- this.m_jsonParser.skipChildren();
- } catch (Exception var2) {
- throw new JsonGeometryException(var2);
- }
- }
-
- public String currentString() throws JsonGeometryException {
- try {
- return this.m_jsonParser.getText();
- } catch (Exception var2) {
- throw new JsonGeometryException(var2);
- }
- }
-
- public double currentDoubleValue() throws JsonGeometryException {
- try {
- return this.m_jsonParser.getValueAsDouble();
- } catch (Exception var2) {
- throw new JsonGeometryException(var2);
- }
- }
-
- public int currentIntValue() throws JsonGeometryException {
- try {
- return this.m_jsonParser.getValueAsInt();
- } catch (Exception var2) {
- throw new JsonGeometryException(var2);
- }
- }
-
- public boolean currentBooleanValue() {
- Token t = this.currentToken();
- if (t == Token.VALUE_TRUE) {
- return true;
- } else if (t == Token.VALUE_FALSE) {
- return false;
- } else {
- throw new JsonGeometryException("Not a boolean");
}
}
}
-
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/serde/GeoJsonSerDe.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/serde/GeoJsonSerDe.java
index a21aa69f46e6..2043fa393e5a 100644
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/serde/GeoJsonSerDe.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/esri/serde/GeoJsonSerDe.java
@@ -17,11 +17,13 @@
*/
package org.apache.hadoop.hive.ql.udf.esri.serde;
-import com.esri.core.geometry.ogc.OGCGeometry;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.apache.hadoop.hive.ql.udf.esri.GeometryUtils;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.io.ParseException;
import java.io.IOException;
@@ -36,20 +38,18 @@ public GeoJsonSerDe() {
}
@Override
- protected String outGeom(OGCGeometry geom) {
- return geom.asGeoJson();
+ protected String outGeom(Geometry geom) {
+ return GeometryUtils.geoJsonWriter().write(geom);
}
@Override
- protected OGCGeometry parseGeom(JsonParser parser) {
+ protected Geometry parseGeom(JsonParser parser) {
try {
ObjectNode node = mapper.readTree(parser);
- return OGCGeometry.fromGeoJson(node.toString());
- } catch (JsonProcessingException e1) {
- e1.printStackTrace(); // TODO Auto-generated catch block
- } catch (IOException e1) {
- e1.printStackTrace(); // TODO Auto-generated catch block
+ return GeometryUtils.geoJsonReader().read(node.toString());
+ } catch (ParseException | IOException e1) {
+ LOG.error("Error parsing GeoJSON", e1);
}
- return null; // ?
+ return null;
}
}
diff --git a/ql/src/test/org/apache/hadoop/hive/ql/udf/esri/TestStCentroid.java b/ql/src/test/org/apache/hadoop/hive/ql/udf/esri/TestStCentroid.java
index fdfffc876aff..722ac7a6a64b 100644
--- a/ql/src/test/org/apache/hadoop/hive/ql/udf/esri/TestStCentroid.java
+++ b/ql/src/test/org/apache/hadoop/hive/ql/udf/esri/TestStCentroid.java
@@ -17,7 +17,6 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.Point;
import org.apache.hadoop.hive.serde2.io.DoubleWritable;
import org.apache.hadoop.io.BytesWritable;
import org.apache.hadoop.io.Text;
@@ -33,25 +32,30 @@ public class TestStCentroid {
/**
* Validates the centroid geometry writable.
*
- * @param point
- * the represented point location.
+ * @param expectedX
+ * the expected X (longitude) of the centroid.
+ * @param expectedY
+ * the expected Y (latitude) of the centroid.
* @param geometryAsWritable
* the geometry represented as {@link BytesWritable}.
*/
- private static void validatePoint(Point point, BytesWritable geometryAsWritable) {
+ private static void validatePoint(double expectedX, double expectedY, BytesWritable geometryAsWritable) {
ST_X getX = new ST_X();
ST_Y getY = new ST_Y();
DoubleWritable xAsWritable = getX.evaluate(geometryAsWritable);
DoubleWritable yAsWritable = getY.evaluate(geometryAsWritable);
- if (null == xAsWritable || null == yAsWritable || Math.abs(point.getX() - xAsWritable.get()) > Epsilon
- || Math.abs(point.getY() - yAsWritable.get()) > Epsilon)
- System.err.println("validateCentroid: " + (new ST_AsText()).evaluate(geometryAsWritable) + " ~ " + point);
+ if (null == xAsWritable || null == yAsWritable || Math.abs(expectedX - xAsWritable.get()) > Epsilon
+ || Math.abs(expectedY - yAsWritable.get()) > Epsilon) {
+ System.err.println(
+ "validateCentroid: " + (new ST_AsText()).evaluate(geometryAsWritable) + " ~ (" + expectedX + ", " + expectedY
+ + ")");
+ }
assertNotNull("The x writable must not be null!", xAsWritable);
assertNotNull("The y writable must not be null!", yAsWritable);
- assertEquals("Longitude is different!", point.getX(), xAsWritable.get(), Epsilon);
- assertEquals("Latitude is different!", point.getY(), yAsWritable.get(), Epsilon);
+ assertEquals("Longitude is different!", expectedX, xAsWritable.get(), Epsilon);
+ assertEquals("Latitude is different!", expectedY, yAsWritable.get(), Epsilon);
}
@Test
@@ -60,7 +64,7 @@ public void TestSimplePointCentroid() throws Exception {
final ST_Point stPt = new ST_Point();
BytesWritable bwGeom = stPt.evaluate(new Text("point (2 3)"));
BytesWritable bwCentroid = stCtr.evaluate(bwGeom);
- validatePoint(new Point(2, 3), bwCentroid);
+ validatePoint(2, 3, bwCentroid);
}
@Test
@@ -69,7 +73,7 @@ public void TestMultiPointCentroid() throws Exception {
final ST_MultiPoint stMp = new ST_MultiPoint();
BytesWritable bwGeom = stMp.evaluate(new Text("multipoint ((0 0), (1 1), (1 -1), (6 0))"));
BytesWritable bwCentroid = stCtr.evaluate(bwGeom);
- validatePoint(new Point(2, 0), bwCentroid);
+ validatePoint(2, 0, bwCentroid);
}
@Test
@@ -78,12 +82,12 @@ public void TestLineCentroid() throws Exception {
final ST_LineString stLn = new ST_LineString();
BytesWritable bwGeom = stLn.evaluate(new Text("linestring (0 0, 6 0)"));
BytesWritable bwCentroid = stCtr.evaluate(bwGeom);
- validatePoint(new Point(3, 0), bwCentroid);
+ validatePoint(3, 0, bwCentroid);
bwGeom = stLn.evaluate(new Text("linestring (0 0, 0 4, 12 4)"));
bwCentroid = stCtr.evaluate(bwGeom);
// L1 = 4, L2 = 12, W1 = 0.25, W2 = 0.75, X = W1 * 0 + W2 * 6, Y = W1 * 2 + W2 * 4
// Or like centroid of multipoint of 1 of (0 2) and 3 of (6 4)
- validatePoint(new Point(4.5, 3.5), bwCentroid);
+ validatePoint(4.5, 3.5, bwCentroid);
}
@Test
@@ -92,13 +96,13 @@ public void TestPolygonCentroid() throws Exception {
final ST_Polygon stPoly = new ST_Polygon();
BytesWritable bwGeom = stPoly.evaluate(new Text("polygon ((0 0, 0 8, 8 8, 8 0, 0 0))"));
BytesWritable bwCentroid = stCtr.evaluate(bwGeom);
- validatePoint(new Point(4, 4), bwCentroid);
+ validatePoint(4, 4, bwCentroid);
bwGeom = stPoly.evaluate(new Text("polygon ((1 1, 5 1, 3 4, 1 1))"));
bwCentroid = stCtr.evaluate(bwGeom);
- validatePoint(new Point(3, 2), bwCentroid);
+ validatePoint(3, 2, bwCentroid);
bwGeom = stPoly.evaluate(new Text("polygon ((14 0, -14 0, -2 24, 2 24, 14 0))"));
bwCentroid = stCtr.evaluate(bwGeom); // Cross-checked with ...
- validatePoint(new Point(0, 9), bwCentroid); // ... omnicalculator.com/math/centroid
+ validatePoint(0, 9, bwCentroid); // ... omnicalculator.com/math/centroid
}
}
diff --git a/ql/src/test/org/apache/hadoop/hive/ql/udf/esri/TestStGeomFromShape.java b/ql/src/test/org/apache/hadoop/hive/ql/udf/esri/TestStGeomFromShape.java
index 659f1bb97bfd..66ad4f0782d2 100644
--- a/ql/src/test/org/apache/hadoop/hive/ql/udf/esri/TestStGeomFromShape.java
+++ b/ql/src/test/org/apache/hadoop/hive/ql/udf/esri/TestStGeomFromShape.java
@@ -17,17 +17,15 @@
*/
package org.apache.hadoop.hive.ql.udf.esri;
-import com.esri.core.geometry.Geometry;
import com.esri.core.geometry.GeometryEngine;
import com.esri.core.geometry.Point;
import com.esri.core.geometry.Polygon;
import com.esri.core.geometry.Polyline;
-import com.esri.core.geometry.SpatialReference;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.serde2.io.DoubleWritable;
import org.apache.hadoop.io.BytesWritable;
import org.apache.hadoop.io.IntWritable;
+import org.locationtech.jts.geom.Geometry;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
@@ -166,13 +164,16 @@ public void testGeomFromLineShape() throws UDFArgumentException {
BytesWritable geometryAsWritable = fromShape.evaluate(shapeAsWritable, wkid);
assertNotNull("The geometry writable must not be null!", geometryAsWritable);
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geometryAsWritable);
- assertNotNull("The OGC geometry must not be null!", ogcGeometry);
-
- Geometry esriGeometry = ogcGeometry.getEsriGeometry();
- assertNotNull("The Esri geometry must not be null!", esriGeometry);
- assertTrue("The geometries are different!",
- GeometryEngine.equals(line, esriGeometry, SpatialReference.create(wkid)));
+ Geometry jtsGeometry = GeometryUtils.geometryFromEsriShape(geometryAsWritable);
+ assertNotNull("The JTS geometry must not be null!", jtsGeometry);
+ assertEquals("The SRID is different!", wkid, jtsGeometry.getSRID());
+ assertEquals("Expected 2 coordinates (line start/end)!", 2, jtsGeometry.getNumPoints());
+ assertEquals("Start X differs!", createFirstLocation().getX(), jtsGeometry.getCoordinates()[0].x, Epsilon);
+ assertEquals("Start Y differs!", createFirstLocation().getY(), jtsGeometry.getCoordinates()[0].y, Epsilon);
+ assertEquals("End X differs!", createSecondLocation().getX(),
+ jtsGeometry.getCoordinates()[jtsGeometry.getNumPoints() - 1].x, Epsilon);
+ assertEquals("End Y differs!", createSecondLocation().getY(),
+ jtsGeometry.getCoordinates()[jtsGeometry.getNumPoints() - 1].y, Epsilon);
}
@Test
@@ -189,13 +190,16 @@ public void testGeomFromPolylineShape() throws UDFArgumentException {
BytesWritable geometryAsWritable = fromShape.evaluate(shapeAsWritable, wkid);
assertNotNull("The geometry writable must not be null!", geometryAsWritable);
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geometryAsWritable);
- assertNotNull("The OGC geometry must not be null!", ogcGeometry);
-
- Geometry esriGeometry = ogcGeometry.getEsriGeometry();
- assertNotNull("The Esri geometry must not be null!", esriGeometry);
- assertTrue("The geometries are different!",
- GeometryEngine.equals(line, esriGeometry, SpatialReference.create(wkid)));
+ Geometry jtsGeometry = GeometryUtils.geometryFromEsriShape(geometryAsWritable);
+ assertNotNull("The JTS geometry must not be null!", jtsGeometry);
+ assertEquals("The SRID is different!", wkid, jtsGeometry.getSRID());
+ assertEquals("Expected 4 points in polyline!", 4, jtsGeometry.getNumPoints());
+ assertEquals("Start X differs!", createFirstLocation().getX(), jtsGeometry.getCoordinates()[0].x, Epsilon);
+ assertEquals("Start Y differs!", createFirstLocation().getY(), jtsGeometry.getCoordinates()[0].y, Epsilon);
+ assertEquals("End X differs!", createFourthLocation().getX(),
+ jtsGeometry.getCoordinates()[jtsGeometry.getNumPoints() - 1].x, Epsilon);
+ assertEquals("End Y differs!", createFourthLocation().getY(),
+ jtsGeometry.getCoordinates()[jtsGeometry.getNumPoints() - 1].y, Epsilon);
}
@Test
@@ -212,12 +216,12 @@ public void testGeomFromPolygonShape() throws UDFArgumentException {
BytesWritable geometryAsWritable = fromShape.evaluate(shapeAsWritable, wkid);
assertNotNull("The geometry writable must not be null!", geometryAsWritable);
- OGCGeometry ogcGeometry = GeometryUtils.geometryFromEsriShape(geometryAsWritable);
- assertNotNull("The OGC geometry must not be null!", ogcGeometry);
-
- Geometry esriGeometry = ogcGeometry.getEsriGeometry();
- assertNotNull("The Esri geometry must not be null!", esriGeometry);
- assertTrue("The geometries are different!",
- GeometryEngine.equals(polygon, esriGeometry, SpatialReference.create(wkid)));
+ Geometry jtsGeometry = GeometryUtils.geometryFromEsriShape(geometryAsWritable);
+ assertNotNull("The JTS geometry must not be null!", jtsGeometry);
+ assertEquals("The SRID is different!", wkid, jtsGeometry.getSRID());
+ assertTrue("Expected a polygon geometry!", jtsGeometry instanceof org.locationtech.jts.geom.Polygon);
+ // Polygon has 4 vertices + closing vertex = 5 points in the exterior ring
+ assertEquals("Expected 5 coordinates in polygon ring!", 5,
+ ((org.locationtech.jts.geom.Polygon) jtsGeometry).getExteriorRing().getNumPoints());
}
}
diff --git a/ql/src/test/org/apache/hadoop/hive/ql/udf/esri/serde/JsonSerDeTestingBase.java b/ql/src/test/org/apache/hadoop/hive/ql/udf/esri/serde/JsonSerDeTestingBase.java
index 1cf4b1253be4..a229d035a8e9 100644
--- a/ql/src/test/org/apache/hadoop/hive/ql/udf/esri/serde/JsonSerDeTestingBase.java
+++ b/ql/src/test/org/apache/hadoop/hive/ql/udf/esri/serde/JsonSerDeTestingBase.java
@@ -17,12 +17,10 @@
*/
package org.apache.hadoop.hive.ql.udf.esri.serde;
-import com.esri.core.geometry.Geometry;
-import com.esri.core.geometry.MapGeometry;
-import com.esri.core.geometry.Point;
-import com.esri.core.geometry.SpatialReference;
-import com.esri.core.geometry.ogc.OGCGeometry;
import org.apache.hadoop.hive.ql.udf.esri.GeometryUtils;
+
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.Point;
import org.apache.hadoop.hive.serde2.AbstractSerDe;
import org.apache.hadoop.hive.serde2.io.ByteWritable;
import org.apache.hadoop.hive.serde2.io.DateWritable;
@@ -100,19 +98,16 @@ protected void addWritable(ArrayList
+
+ org.locationtech.jts
+ jts-core
+ ${jts.version}
+ compile
+ org.mockitomockito-core
diff --git a/serde/src/java/org/apache/hadoop/hive/serde2/esriJson/deserializer/GeometryJsonDeserializer.java b/serde/src/java/org/apache/hadoop/hive/serde2/esriJson/deserializer/GeometryJsonDeserializer.java
index 3ccf8607f8d9..b55e9f39aa61 100755
--- a/serde/src/java/org/apache/hadoop/hive/serde2/esriJson/deserializer/GeometryJsonDeserializer.java
+++ b/serde/src/java/org/apache/hadoop/hive/serde2/esriJson/deserializer/GeometryJsonDeserializer.java
@@ -17,27 +17,51 @@
*/
package org.apache.hadoop.hive.serde2.esriJson.deserializer;
-import com.esri.core.geometry.Geometry;
import com.esri.core.geometry.GeometryEngine;
+import com.esri.core.geometry.MapGeometry;
+import com.esri.core.geometry.ogc.OGCGeometry;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.GeometryFactory;
+import org.locationtech.jts.io.WKBReader;
import java.io.IOException;
/**
*
- * Deserializes a JSON geometry definition into a Geometry instance
+ * Deserializes a JSON geometry definition into a JTS Geometry instance.
+ * Uses the ESRI API to parse Esri JSON, then converts to JTS via WKB round-trip.
*/
public class GeometryJsonDeserializer extends JsonDeserializer {
+ private static final GeometryFactory GEOMETRY_FACTORY = new GeometryFactory();
+
public GeometryJsonDeserializer() {
}
@Override
public Geometry deserialize(JsonParser arg0, DeserializationContext arg1)
throws IOException, JsonProcessingException {
- return GeometryEngine.jsonToGeometry(arg0).getGeometry();
+ try {
+ MapGeometry mapGeom = GeometryEngine.jsonToGeometry(arg0);
+ if (mapGeom == null || mapGeom.getGeometry() == null) {
+ return null;
+ }
+ OGCGeometry ogcGeom = OGCGeometry.createFromEsriGeometry(
+ mapGeom.getGeometry(), mapGeom.getSpatialReference());
+ java.nio.ByteBuffer wkbBuf = ogcGeom.asBinary();
+ byte[] wkbBytes = new byte[wkbBuf.remaining()];
+ wkbBuf.get(wkbBytes);
+ Geometry jtsGeom = new WKBReader(GEOMETRY_FACTORY).read(wkbBytes);
+ if (mapGeom.getSpatialReference() != null) {
+ jtsGeom.setSRID(mapGeom.getSpatialReference().getID());
+ }
+ return jtsGeom;
+ } catch (Exception e) {
+ return null;
+ }
}
}
diff --git a/serde/src/java/org/apache/hadoop/hive/serde2/esriJson/deserializer/GeometryTypeJsonDeserializer.java b/serde/src/java/org/apache/hadoop/hive/serde2/esriJson/deserializer/GeometryTypeJsonDeserializer.java
index 7b93f5e0b85d..7a98d655f782 100755
--- a/serde/src/java/org/apache/hadoop/hive/serde2/esriJson/deserializer/GeometryTypeJsonDeserializer.java
+++ b/serde/src/java/org/apache/hadoop/hive/serde2/esriJson/deserializer/GeometryTypeJsonDeserializer.java
@@ -17,7 +17,6 @@
*/
package org.apache.hadoop.hive.serde2.esriJson.deserializer;
-import com.esri.core.geometry.Geometry;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
@@ -27,32 +26,26 @@
/**
*
- * Deserializes a JSON geometry type enumeration into a Geometry.Type.* enumeration
+ * Deserializes a JSON geometry type string (e.g. "esriGeometryPolygon") into a String.
+ * The raw Esri geometry type string is preserved as-is for downstream use.
*/
-public class GeometryTypeJsonDeserializer extends JsonDeserializer {
+public class GeometryTypeJsonDeserializer extends JsonDeserializer {
public GeometryTypeJsonDeserializer() {
}
@Override
- public Geometry.Type deserialize(JsonParser parser, DeserializationContext arg1)
+ public String deserialize(JsonParser parser, DeserializationContext arg1)
throws IOException, JsonProcessingException {
-
String type_text = parser.getText();
-
- // geometry type enumerations coming from the JSON are prepended with "esriGeometry" (i.e. esriGeometryPolygon)
- // while the geometry-java-api uses the form Geometry.Type.Polygon
- if (type_text.startsWith("esriGeometry")) {
- // cut out esriGeometry to match Geometry.Type enumeration values
- type_text = type_text.substring(12);
-
- try {
- return Enum.valueOf(Geometry.Type.class, type_text);
- } catch (Exception e) {
- // parsing failed, fall through to unknown geometry type
- }
+ if (type_text == null) {
+ return "esriGeometryUnknown";
}
-
- return Geometry.Type.Unknown;
+ // Preserve the raw esriGeometry* string (e.g. "esriGeometryPolygon").
+ // If the value is not already prefixed, normalise it.
+ if (!type_text.startsWith("esriGeometry")) {
+ return "esriGeometry" + type_text;
+ }
+ return type_text;
}
}
diff --git a/serde/src/java/org/apache/hadoop/hive/serde2/esriJson/deserializer/SpatialReferenceJsonDeserializer.java b/serde/src/java/org/apache/hadoop/hive/serde2/esriJson/deserializer/SpatialReferenceJsonDeserializer.java
index a1e38ee04df0..85460b3cbc8a 100755
--- a/serde/src/java/org/apache/hadoop/hive/serde2/esriJson/deserializer/SpatialReferenceJsonDeserializer.java
+++ b/serde/src/java/org/apache/hadoop/hive/serde2/esriJson/deserializer/SpatialReferenceJsonDeserializer.java
@@ -17,9 +17,9 @@
*/
package org.apache.hadoop.hive.serde2.esriJson.deserializer;
-import com.esri.core.geometry.SpatialReference;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
@@ -27,20 +27,39 @@
/**
*
- * Deserializes a JSON spatial reference definition into a SpatialReference instance
+ * Deserializes a JSON spatial reference definition into an integer SRID (WKID).
+ * Reads the "wkid" field from the spatialReference JSON object.
+ * Returns 0 if the spatial reference is absent or cannot be parsed.
*/
-public class SpatialReferenceJsonDeserializer extends JsonDeserializer {
+public class SpatialReferenceJsonDeserializer extends JsonDeserializer {
public SpatialReferenceJsonDeserializer() {
}
@Override
- public SpatialReference deserialize(JsonParser parser, DeserializationContext arg1)
+ public Integer deserialize(JsonParser parser, DeserializationContext arg1)
throws IOException, JsonProcessingException {
try {
- return SpatialReference.fromJson(parser);
+ // The parser is currently positioned at the START_OBJECT token for spatialReference.
+ // Walk through the object looking for the "wkid" field.
+ int wkid = 0;
+ JsonToken token = parser.getCurrentToken();
+ if (token == JsonToken.START_OBJECT) {
+ token = parser.nextToken();
+ }
+ while (token != null && token != JsonToken.END_OBJECT) {
+ if (token == JsonToken.FIELD_NAME) {
+ String fieldName = parser.getCurrentName();
+ parser.nextToken();
+ if ("wkid".equalsIgnoreCase(fieldName) || "latestWkid".equalsIgnoreCase(fieldName)) {
+ wkid = parser.getIntValue();
+ }
+ }
+ token = parser.nextToken();
+ }
+ return wkid;
} catch (Exception e) {
- return null;
+ return 0;
}
}
}
diff --git a/serde/src/java/org/apache/hadoop/hive/serde2/esriJson/serializer/GeometryJsonSerializer.java b/serde/src/java/org/apache/hadoop/hive/serde2/esriJson/serializer/GeometryJsonSerializer.java
index a653057819a2..8f0123997344 100644
--- a/serde/src/java/org/apache/hadoop/hive/serde2/esriJson/serializer/GeometryJsonSerializer.java
+++ b/serde/src/java/org/apache/hadoop/hive/serde2/esriJson/serializer/GeometryJsonSerializer.java
@@ -17,19 +17,32 @@
*/
package org.apache.hadoop.hive.serde2.esriJson.serializer;
-import com.esri.core.geometry.Geometry;
import com.esri.core.geometry.GeometryEngine;
+import com.esri.core.geometry.ogc.OGCGeometry;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.io.WKBWriter;
import java.io.IOException;
+/**
+ * Serializes a JTS Geometry to Esri JSON format.
+ * Converts JTS -> ESRI via WKB round-trip, then uses GeometryEngine.geometryToJson().
+ */
public class GeometryJsonSerializer extends JsonSerializer {
@Override
public void serialize(Geometry geometry, JsonGenerator jsonGenerator, SerializerProvider arg2) throws IOException {
-
- jsonGenerator.writeRawValue(GeometryEngine.geometryToJson(null, geometry));
+ try {
+ byte[] wkb = new WKBWriter().write(geometry);
+ OGCGeometry ogcGeom = OGCGeometry.fromBinary(java.nio.ByteBuffer.wrap(wkb));
+ com.esri.core.geometry.Geometry esriGeom = ogcGeom.getEsriGeometry();
+ int wkid = geometry.getSRID();
+ jsonGenerator.writeRawValue(GeometryEngine.geometryToJson(wkid, esriGeom));
+ } catch (Exception e) {
+ jsonGenerator.writeNull();
+ }
}
}
diff --git a/serde/src/java/org/apache/hadoop/hive/serde2/esriJson/serializer/GeometryTypeJsonSerializer.java b/serde/src/java/org/apache/hadoop/hive/serde2/esriJson/serializer/GeometryTypeJsonSerializer.java
index 1c7932bce621..5775b5a9319c 100644
--- a/serde/src/java/org/apache/hadoop/hive/serde2/esriJson/serializer/GeometryTypeJsonSerializer.java
+++ b/serde/src/java/org/apache/hadoop/hive/serde2/esriJson/serializer/GeometryTypeJsonSerializer.java
@@ -17,7 +17,6 @@
*/
package org.apache.hadoop.hive.serde2.esriJson.serializer;
-import com.esri.core.geometry.Geometry.Type;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
@@ -25,11 +24,24 @@
import java.io.IOException;
-public class GeometryTypeJsonSerializer extends JsonSerializer {
+/**
+ * Serializes a geometry type String (e.g. "esriGeometryPolygon") to JSON.
+ * The String is already in the Esri "esriGeometry*" form as produced by
+ * GeometryTypeJsonDeserializer; it is written verbatim.
+ */
+public class GeometryTypeJsonSerializer extends JsonSerializer {
@Override
- public void serialize(Type geometryType, JsonGenerator jsonGenerator, SerializerProvider arg2)
+ public void serialize(String geometryType, JsonGenerator jsonGenerator, SerializerProvider arg2)
throws IOException, JsonProcessingException {
- jsonGenerator.writeString("esriGeometry" + geometryType);
+ if (geometryType == null) {
+ jsonGenerator.writeNull();
+ } else if (geometryType.startsWith("esriGeometry")) {
+ // Already in canonical form — write as-is
+ jsonGenerator.writeString(geometryType);
+ } else {
+ // Normalise bare type names (e.g. "Polygon" -> "esriGeometryPolygon")
+ jsonGenerator.writeString("esriGeometry" + geometryType);
+ }
}
}
diff --git a/serde/src/java/org/apache/hadoop/hive/serde2/esriJson/serializer/SpatialReferenceJsonSerializer.java b/serde/src/java/org/apache/hadoop/hive/serde2/esriJson/serializer/SpatialReferenceJsonSerializer.java
index 66e32364da8b..295e9c3a6fa9 100644
--- a/serde/src/java/org/apache/hadoop/hive/serde2/esriJson/serializer/SpatialReferenceJsonSerializer.java
+++ b/serde/src/java/org/apache/hadoop/hive/serde2/esriJson/serializer/SpatialReferenceJsonSerializer.java
@@ -17,7 +17,6 @@
*/
package org.apache.hadoop.hive.serde2.esriJson.serializer;
-import com.esri.core.geometry.SpatialReference;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
@@ -25,17 +24,16 @@
import java.io.IOException;
-public class SpatialReferenceJsonSerializer extends JsonSerializer {
+/**
+ * Serializes an integer SRID (WKID) as a JSON spatialReference object: {"wkid": }.
+ */
+public class SpatialReferenceJsonSerializer extends JsonSerializer {
@Override
- public void serialize(SpatialReference spatialReference, JsonGenerator jsonGenerator, SerializerProvider arg2)
+ public void serialize(Integer wkid, JsonGenerator jsonGenerator, SerializerProvider arg2)
throws IOException, JsonProcessingException {
-
- int wkid = spatialReference.getID();
-
jsonGenerator.writeStartObject();
- jsonGenerator.writeObjectField("wkid", wkid);
+ jsonGenerator.writeObjectField("wkid", wkid == null ? 0 : wkid);
jsonGenerator.writeEndObject();
}
-
}