You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by js...@apache.org on 2022/02/17 15:13:50 UTC
[sis] 01/01: PostGIS: add HexEWKB geometry reader
This is an automated email from the ASF dual-hosted git repository.
jsorel pushed a commit to branch feat/postgis-hexewkb
in repository https://gitbox.apache.org/repos/asf/sis.git
commit e34e693f46188689f697694a9eccc56b91b01ca5
Author: jsorel <jo...@geomatys.com>
AuthorDate: Thu Feb 17 16:06:43 2022 +0100
PostGIS: add HexEWKB geometry reader
---
storage/sis-sqlstore/pom.xml | 7 +-
.../apache/sis/internal/sql/postgis/HexEWKB.java | 193 +++++++++++++++++++++
2 files changed, 199 insertions(+), 1 deletion(-)
diff --git a/storage/sis-sqlstore/pom.xml b/storage/sis-sqlstore/pom.xml
index 3053c18..e057e31 100644
--- a/storage/sis-sqlstore/pom.xml
+++ b/storage/sis-sqlstore/pom.xml
@@ -111,6 +111,11 @@
<version>${project.version}</version>
</dependency>
<dependency>
+ <groupId>net.postgis</groupId>
+ <artifactId>postgis-jdbc</artifactId>
+ <version>2.3.0</version>
+ </dependency>
+ <dependency>
<groupId>org.apache.sis.core</groupId>
<artifactId>sis-metadata</artifactId>
<version>${project.version}</version>
@@ -147,7 +152,7 @@
<dependency>
<groupId>org.locationtech.jts</groupId>
<artifactId>jts-core</artifactId>
- <scope>test</scope>
+ <scope>compile</scope>
</dependency>
<dependency>
<groupId>com.esri.geometry</groupId>
diff --git a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/postgis/HexEWKB.java b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/postgis/HexEWKB.java
new file mode 100644
index 0000000..041cf9f
--- /dev/null
+++ b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/postgis/HexEWKB.java
@@ -0,0 +1,193 @@
+/*
+ * 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.sis.internal.sql.postgis;
+
+import org.locationtech.jts.geom.Coordinate;
+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.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 org.locationtech.jts.geom.impl.PackedCoordinateSequence;
+import org.postgis.binary.ByteGetter;
+import org.postgis.binary.ValueGetter;
+import static org.postgis.Geometry.*;
+
+/**
+ * PostGIS Hexa-EWKB Geometry reader/write classes.
+ *
+ * This format is the natural form returned by a query selection a geometry
+ * field whithout using any ST_X method.
+ *
+ * @see <a href="http://postgis.net/docs/using_postgis_dbmanagement.html#EWKB_EWKT">4.2.1. PostGIS EWKB and EWKT</a>
+ *
+ * @author Johann Sorel (Geomatys)
+ * @module
+ */
+final class PostgisHexEWKB {
+
+ private static final int MASK_Z = 0x80000000;
+ private static final int MASK_M = 0x40000000;
+ private static final int MASK_SRID = 0x20000000;
+ private static final int MASK_GEOMTYPE = 0x1FFFFFFF;
+
+ private final GeometryFactory gf;
+
+ PostgisHexEWKB(final GeometryFactory gf) {
+ this.gf = gf;
+ }
+
+ public Geometry read(final String value) {
+ if (value == null) {
+ return null;
+ }
+
+ final ByteGetter.StringByteGetter bytes = new ByteGetter.StringByteGetter(value);
+ final ValueGetter vg;
+ final int endianess = bytes.get(0);
+ if (endianess == ValueGetter.XDR.NUMBER) {
+ vg = new ValueGetter.XDR(bytes);
+ } else if (endianess == ValueGetter.NDR.NUMBER) {
+ vg = new ValueGetter.NDR(bytes);
+ } else {
+ throw new IllegalArgumentException("Illegal endianess value : " + endianess);
+ }
+
+ return readGeometry(vg, 0);
+ }
+
+ private Geometry readGeometry(final ValueGetter data, int srid) {
+ byte endian = data.getByte(); // skip and test endian flag
+ if (endian != data.endian) {
+ throw new IllegalArgumentException("Endian inconsistency!");
+ }
+
+ //parse flags
+ final int flags = data.getInt();
+ final boolean flagZ = (flags & MASK_Z) != 0;
+ final boolean flagM = (flags & MASK_M) != 0;
+ final boolean flagSRID = (flags & MASK_SRID) != 0;
+ final int geomType = (flags & MASK_GEOMTYPE);
+ final int nbDim = 2 + ((flagZ) ? 1 : 0) + ((flagM) ? 1 : 0);
+
+ if (flagSRID) {
+ srid = data.getInt();
+ }
+
+ final Geometry geom;
+ switch (geomType) {
+ case POINT: geom = readPoint(data, nbDim); break;
+ case LINESTRING: geom = readLineString(data, nbDim); break;
+ case POLYGON: geom = readPolygon(data, nbDim, srid); break;
+ case MULTIPOINT: geom = readMultiPoint(data, srid); break;
+ case MULTILINESTRING: geom = readMultiLineString(data, srid); break;
+ case MULTIPOLYGON: geom = readMultiPolygon(data, srid); break;
+ case GEOMETRYCOLLECTION: geom = readCollection(data, srid); break;
+ default: throw new IllegalArgumentException("Unknown geometry type : "+geomType);
+ }
+
+ geom.setSRID(srid);
+ return geom;
+ }
+
+ private Point readPoint(final ValueGetter data, final int nbDim) {
+ switch (nbDim) {
+ case 2:
+ return gf.createPoint(new Coordinate(data.getDouble(), data.getDouble()));
+ case 3:
+ return gf.createPoint(new Coordinate(data.getDouble(), data.getDouble(), data.getDouble()));
+ case 4:
+ final CoordinateSequence cs = new PackedCoordinateSequence.Double(1, nbDim, 0);
+ cs.setOrdinate(0, 0, data.getDouble());
+ cs.setOrdinate(0, 1, data.getDouble());
+ cs.setOrdinate(0, 2, data.getDouble());
+ cs.setOrdinate(0, 3, data.getDouble());
+ return gf.createPoint(cs);
+ default:
+ throw new IllegalArgumentException("Invalid dimension number : " + nbDim);
+ }
+ }
+
+ private CoordinateSequence readCS(final ValueGetter data, final int nbDim) {
+ final int nb = data.getInt();
+ final CoordinateSequence cs = new PackedCoordinateSequence.Double(nb, nbDim, 0);
+ for (int index = 0; index < nb; index++) {
+ for (int ordinal = 0; ordinal < nbDim; ordinal++) {
+ cs.setOrdinate(index, ordinal, data.getDouble());
+ }
+ }
+ return cs;
+ }
+
+ private MultiPoint readMultiPoint(final ValueGetter data, final int srid) {
+ final Point[] geoms = new Point[data.getInt()];
+ for (int i = 0; i < geoms.length; i++) {
+ geoms[i] = (Point) readGeometry(data, srid);
+ }
+ return gf.createMultiPoint(geoms);
+ }
+
+ private LineString readLineString(final ValueGetter data, final int nbDim) {
+ return gf.createLineString(readCS(data, nbDim));
+ }
+
+ private LinearRing readLinearRing(final ValueGetter data, final int nbDim) {
+ return gf.createLinearRing(readCS(data, nbDim));
+ }
+
+ private Polygon readPolygon(final ValueGetter data, final int nbDim, final int srid) {
+ final LinearRing[] inners = new LinearRing[data.getInt() - 1];
+ final LinearRing outter = readLinearRing(data, nbDim);
+ outter.setSRID(srid);
+ for (int i = 0; i < inners.length; i++) {
+ inners[i] = readLinearRing(data, nbDim);
+ inners[i].setSRID(srid);
+ }
+ return gf.createPolygon(outter, inners);
+ }
+
+ private MultiLineString readMultiLineString(final ValueGetter data, final int srid) {
+ final LineString[] geoms = new LineString[data.getInt()];
+ for (int i = 0; i < geoms.length; i++) {
+ geoms[i] = (LineString) readGeometry(data, srid);
+ }
+ return gf.createMultiLineString(geoms);
+ }
+
+ private MultiPolygon readMultiPolygon(final ValueGetter data, final int srid) {
+ final Polygon[] geoms = new Polygon[data.getInt()];
+ for (int i = 0; i < geoms.length; i++) {
+ geoms[i] = (Polygon) readGeometry(data, srid);
+ }
+ return gf.createMultiPolygon(geoms);
+ }
+
+ private GeometryCollection readCollection(final ValueGetter data, final int srid) {
+ final Geometry[] geoms = new Geometry[data.getInt()];
+ for (int i = 0; i < geoms.length; i++) {
+ geoms[i] = (Point) readGeometry(data, srid);
+ }
+ return gf.createGeometryCollection(geoms);
+ }
+
+}