This is an automated email from the ASF dual-hosted git repository. malka pushed a commit to branch SEDONA-17_Rdd2WKBSer in repository https://gitbox.apache.org/repos/asf/incubator-sedona.git
commit 0b3ba5146830e256bda5ee1c6546c35197a26655 Author: Netanel Malka <[email protected]> AuthorDate: Tue Feb 23 23:05:17 2021 +0200 Used WKB serde instead of the ShapeSerde Removed unused ShapeSerde.java --- .../shapefileParser/parseUtils/shp/ShapeSerde.java | 264 --------------------- .../sedona/core/geometryObjects/GeometrySerde.java | 49 ++-- 2 files changed, 33 insertions(+), 280 deletions(-) diff --git a/core/src/main/java/org/apache/sedona/core/formatMapper/shapefileParser/parseUtils/shp/ShapeSerde.java b/core/src/main/java/org/apache/sedona/core/formatMapper/shapefileParser/parseUtils/shp/ShapeSerde.java deleted file mode 100644 index 0d0ffcc..0000000 --- a/core/src/main/java/org/apache/sedona/core/formatMapper/shapefileParser/parseUtils/shp/ShapeSerde.java +++ /dev/null @@ -1,264 +0,0 @@ -/* - * 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.sedona.core.formatMapper.shapefileParser.parseUtils.shp; - -import com.esotericsoftware.kryo.io.Input; -import org.locationtech.jts.geom.Geometry; -import org.locationtech.jts.geom.GeometryFactory; -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; - -/** - * Provides methods to efficiently serialize and deserialize geometry types - * using shapefile format developed by ESRI. Does not serialize user data - * attached to the geometry. - * <p> - * Supports Point, LineString, Polygon, MultiPoint, MultiLineString and - * MultiPolygon types. - * <p> - * Compatible with the family of {@link ShapeReader} classes. - * <p> - * First byte contains {@link ShapeType#id}. The rest is type specific. - * Point: 8 bytes for X coordinate, followed by 8 bytes for Y coordinate. - * LineString is serialized as MultiLineString. - * MultiLineString: 16 bytes for envelope, 4 bytes for the number of line strings, - * 4 bytes for total number of vertexes, 16 * num-vertexes for - * XY coordinates of all the vertexes. - * Polygons is serialized as MultiPolygon. - * MultiPolygon: 16 bytes for envelope, 4 bytes for the total number of exterior and - * interior rings of all polygons, 4 bytes for total number of vertexes, - * 16 * num-vertexes for XY coordinates of all the vertexes. The vertexes - * are written one polygon at a time, exterior ring first, followed by - * interior rings. - */ -public class ShapeSerde -{ - private static final int POINT_LENGTH = 1 + 2 * ShapeFileConst.DOUBLE_LENGTH; - - public static byte[] serialize(Geometry geometry) - { - if (geometry instanceof Point) { - return serialize((Point) geometry); - } - - if (geometry instanceof MultiPoint) { - return serialize((MultiPoint) geometry); - } - - if (geometry instanceof LineString) { - return serialize((LineString) geometry); - } - - if (geometry instanceof MultiLineString) { - return serialize((MultiLineString) geometry); - } - - if (geometry instanceof Polygon) { - return serialize((Polygon) geometry); - } - - if (geometry instanceof MultiPolygon) { - return serialize((MultiPolygon) geometry); - } - - throw new UnsupportedOperationException("Geometry type is not supported: " + - geometry.getClass().getSimpleName()); - } - - public static Geometry deserialize(Input input, GeometryFactory factory) - { - ShapeReader reader = ShapeReaderFactory.fromInput(input); - ShapeType type = ShapeType.getType(reader.readByte()); - ShapeParser parser = type.getParser(factory); - return parser.parseShape(reader); - } - - public static Geometry deserialize(byte[] input, GeometryFactory factory) - { - ShapeReader reader = ShapeReaderFactory.fromByteBuffer(ByteBuffer.wrap(input)); - ShapeType type = ShapeType.getType(reader.readByte()); - ShapeParser parser = type.getParser(factory); - return parser.parseShape(reader); - } - - private static byte[] serialize(Point point) - { - ByteBuffer buffer = newBuffer(POINT_LENGTH); - putType(buffer, ShapeType.POINT); - buffer.putDouble(point.getX()); - buffer.putDouble(point.getY()); - - return buffer.array(); - } - - private static void putType(ByteBuffer buffer, ShapeType type) - { - buffer.put((byte) type.getId()); - } - - private static byte[] serialize(MultiPoint multiPoint) - { - int numPoints = multiPoint.getNumPoints(); - - ByteBuffer buffer = newBuffer(calculateBufferSize(multiPoint)); - putType(buffer, ShapeType.MULTIPOINT); - buffer.position(buffer.position() + 4 * ShapeFileConst.DOUBLE_LENGTH); - buffer.putInt(numPoints); - for (int i = 0; i < numPoints; i++) { - Point point = (Point) multiPoint.getGeometryN(i); - buffer.putDouble(point.getX()); - buffer.putDouble(point.getY()); - } - return buffer.array(); - } - - private static int calculateBufferSize(MultiPoint multiPoint) - { - return 1 + 4 * ShapeFileConst.DOUBLE_LENGTH + ShapeFileConst.INT_LENGTH + multiPoint.getNumPoints() * 2 * ShapeFileConst.DOUBLE_LENGTH; - } - - private static byte[] serialize(LineString lineString) - { - int numPoints = lineString.getNumPoints(); - - ByteBuffer buffer = newBuffer(calculateBufferSize(numPoints, 1)); - putHeader(buffer, ShapeType.POLYLINE, numPoints, 1); - buffer.putInt(0); - putPoints(buffer, lineString); - return buffer.array(); - } - - private static int calculateBufferSize(int numPoints, int numParts) - { - return 1 + 4 * ShapeFileConst.DOUBLE_LENGTH + ShapeFileConst.INT_LENGTH + ShapeFileConst.INT_LENGTH + numParts * ShapeFileConst.INT_LENGTH + numPoints * 2 * ShapeFileConst.DOUBLE_LENGTH; - } - - private static void putHeader(ByteBuffer buffer, ShapeType type, int numPoints, int numParts) - { - putType(buffer, type); - buffer.position(buffer.position() + 4 * ShapeFileConst.DOUBLE_LENGTH); - buffer.putInt(numParts); - buffer.putInt(numPoints); - } - - private static byte[] serialize(MultiLineString multiLineString) - { - int numPoints = multiLineString.getNumPoints(); - int numParts = multiLineString.getNumGeometries(); - - ByteBuffer buffer = newBuffer(calculateBufferSize(numPoints, numParts)); - putHeader(buffer, ShapeType.POLYLINE, numPoints, numParts); - - int offset = 0; - for (int i = 0; i < numParts; i++) { - buffer.putInt(offset); - offset += multiLineString.getGeometryN(i).getNumPoints(); - } - - for (int i = 0; i < numParts; i++) { - putPoints(buffer, (LineString) multiLineString.getGeometryN(i)); - } - return buffer.array(); - } - - private static byte[] serialize(Polygon polygon) - { - int numRings = polygon.getNumInteriorRing() + 1; - int numPoints = polygon.getNumPoints(); - - ByteBuffer buffer = newBuffer(calculateBufferSize(numPoints, numRings)); - putHeader(buffer, ShapeType.POLYGON, numPoints, numRings); - putRingOffsets(buffer, polygon, 0); - putPolygonPoints(buffer, polygon); - return buffer.array(); - } - - private static int putRingOffsets(ByteBuffer buffer, Polygon polygon, int initialOffset) - { - int offset = initialOffset; - int numRings = polygon.getNumInteriorRing() + 1; - - buffer.putInt(offset); - offset += polygon.getExteriorRing().getNumPoints(); - for (int i = 0; i < numRings - 1; i++) { - buffer.putInt(offset); - offset += polygon.getInteriorRingN(i).getNumPoints(); - } - - return offset; - } - - private static byte[] serialize(MultiPolygon multiPolygon) - { - int numPolygons = multiPolygon.getNumGeometries(); - int numPoints = multiPolygon.getNumPoints(); - - int numRings = 0; - for (int i = 0; i < numPolygons; i++) { - Polygon polygon = (Polygon) multiPolygon.getGeometryN(i); - numRings += polygon.getNumInteriorRing() + 1; - } - - ByteBuffer buffer = newBuffer(calculateBufferSize(numPoints, numRings)); - putHeader(buffer, ShapeType.POLYGON, numPoints, numRings); - - int offset = 0; - for (int i = 0; i < numPolygons; i++) { - Polygon polygon = (Polygon) multiPolygon.getGeometryN(i); - offset = putRingOffsets(buffer, polygon, offset); - } - - for (int i = 0; i < numPolygons; i++) { - Polygon polygon = (Polygon) multiPolygon.getGeometryN(i); - putPolygonPoints(buffer, polygon); - } - return buffer.array(); - } - - private static void putPolygonPoints(ByteBuffer buffer, Polygon polygon) - { - putPoints(buffer, polygon.getExteriorRing()); - for (int i = 0; i < polygon.getNumInteriorRing(); i++) { - putPoints(buffer, polygon.getInteriorRingN(i)); - } - } - - private static void putPoints(ByteBuffer buffer, LineString geometry) - { - int numPoints = geometry.getNumPoints(); - for (int i = 0; i < numPoints; i++) { - Point point = geometry.getPointN(i); - buffer.putDouble(point.getX()); - buffer.putDouble(point.getY()); - } - } - - private static ByteBuffer newBuffer(int size) - { - return ByteBuffer.allocate(size).order(ByteOrder.LITTLE_ENDIAN); - } -} diff --git a/core/src/main/java/org/apache/sedona/core/geometryObjects/GeometrySerde.java b/core/src/main/java/org/apache/sedona/core/geometryObjects/GeometrySerde.java index 213e8f2..a32d568 100755 --- a/core/src/main/java/org/apache/sedona/core/geometryObjects/GeometrySerde.java +++ b/core/src/main/java/org/apache/sedona/core/geometryObjects/GeometrySerde.java @@ -19,13 +19,14 @@ package org.apache.sedona.core.geometryObjects; +import java.util.Objects; + import com.esotericsoftware.kryo.Kryo; import com.esotericsoftware.kryo.Registration; import com.esotericsoftware.kryo.Serializer; import com.esotericsoftware.kryo.io.Input; import com.esotericsoftware.kryo.io.Output; import org.apache.log4j.Logger; -import org.apache.sedona.core.formatMapper.shapefileParser.parseUtils.shp.ShapeSerde; import org.locationtech.jts.geom.Envelope; import org.locationtech.jts.geom.Geometry; import org.locationtech.jts.geom.GeometryCollection; @@ -36,15 +37,18 @@ 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 org.locationtech.jts.io.ParseException; +import org.locationtech.jts.io.WKBReader; +import org.locationtech.jts.io.WKBWriter; /** - * Provides methods to efficiently serialize and deserialize geometry types. + * Provides methods to efficiently serialize and deserialize geometry types using the WKB format * <p> - * Supports Point, LineString, Polygon, MultiPoint, MultiLineString, MultiPolygon, - * GeometryCollection, Circle and Envelope types. + * Supports Point, LineString, Polygon, MultiPoint, MultiLineString, + * MultiPolygon, GeometryCollection, Circle and Envelope types. * <p> - * First byte contains {@link Type#id}. Then go type-specific bytes, followed - * by user-data attached to the geometry. + * First byte contains {@link Type#id}. Then go type-specific bytes, followed by + * user-data attached to the geometry. */ public class GeometrySerde extends Serializer @@ -99,13 +103,16 @@ public class GeometrySerde private void writeGeometry(Kryo kryo, Output out, Geometry geometry) { - byte[] data = ShapeSerde.serialize(geometry); + WKBWriter writer = new WKBWriter(2, 2, true); + byte[] data = writer.write(geometry); + + // write geometry length size to read bytes until userData + out.writeInt(data.length, true); out.write(data, 0, data.length); writeUserData(kryo, out, geometry); } - private void writeUserData(Kryo kryo, Output out, Geometry geometry) - { + private void writeUserData(Kryo kryo, Output out, Geometry geometry) { out.writeBoolean(geometry.getUserData() != null); if (geometry.getUserData() != null) { kryo.writeClass(out, geometry.getUserData().getClass()); @@ -118,7 +125,7 @@ public class GeometrySerde { byte typeId = input.readByte(); Type geometryType = Type.fromId(typeId); - switch (geometryType) { + switch (Objects.requireNonNull(geometryType)) { case SHAPE: return readGeometry(kryo, input); case CIRCLE: { @@ -153,8 +160,7 @@ public class GeometrySerde } } - private Object readUserData(Kryo kryo, Input input) - { + private Object readUserData(Kryo kryo, Input input) { Object userData = null; if (input.readBoolean()) { Registration clazz = kryo.readClass(input); @@ -163,10 +169,21 @@ public class GeometrySerde return userData; } - private Geometry readGeometry(Kryo kryo, Input input) - { - Geometry geometry = ShapeSerde.deserialize(input, geometryFactory); - geometry.setUserData(readUserData(kryo, input)); + private Geometry readGeometry(Kryo kryo, Input input) { + WKBReader reader = new WKBReader(); + Geometry geometry; + + int geometryBytesLength = input.readInt(true); + byte[] bytes = input.readBytes(geometryBytesLength); + + try { + geometry = reader.read(bytes); + geometry.setUserData(readUserData(kryo, input)); + } catch (ParseException e) { + log.error("Cannot parse geometry bytes", e); + return null; + } + return geometry; }
