提交 03f79615 authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov

Add SRID support to EWKT format that is de-facto used instead of WKT anyway

上级 40418025
...@@ -2895,9 +2895,10 @@ ENUM('clubs', 'diamonds', 'hearts', 'spades') ...@@ -2895,9 +2895,10 @@ ENUM('clubs', 'diamonds', 'hearts', 'spades')
GEOMETRY GEOMETRY
"," ","
A spatial geometry type, based on the ""org.locationtech.jts"" library. A spatial geometry type, based on the ""org.locationtech.jts"" library.
Normally represented in textual format using the WKT (well known text) format. May be represented in textual format using the WKT (well-known text) or EWKT (extended well-known text) format.
Values are stored internally in EWKB (extended well-known binary) format.
Use a quoted string containing a WKT formatted string or ""PreparedStatement.setObject()"" to store values, Use a quoted string containing a WKT/EWKT formatted string or ""PreparedStatement.setObject()"" to store values,
and ""ResultSet.getObject(..)"" or ""ResultSet.getString(..)"" to retrieve the values. and ""ResultSet.getObject(..)"" or ""ResultSet.getString(..)"" to retrieve the values.
"," ","
GEOMETRY GEOMETRY
......
...@@ -100,31 +100,25 @@ public class ValueGeometry extends Value { ...@@ -100,31 +100,25 @@ public class ValueGeometry extends Value {
/** /**
* Get or create a geometry value for the given geometry. * Get or create a geometry value for the given geometry.
* *
* @param s the WKT representation of the geometry * @param s the WKT or EWKT representation of the geometry
* @return the value * @return the value
*/ */
public static ValueGeometry get(String s) { public static ValueGeometry get(String s) {
try { try {
Geometry g = new WKTReader().read(s); int srid;
return get(g); if (s.startsWith("SRID=")) {
} catch (ParseException ex) { int idx = s.indexOf(';', 5);
throw DbException.convert(ex); srid = Integer.parseInt(s.substring(5, idx));
} s = s.substring(idx + 1);
} else {
srid = 0;
} }
/*
/** * No-arg WKTReader() constructor instantiates a new GeometryFactory and a new
* Get or create a geometry value for the given geometry. * PrecisionModel anyway, so special case for srid == 0 is not needed.
*
* @param s the WKT representation of the geometry
* @param srid the srid of the object
* @return the value
*/ */
public static ValueGeometry get(String s, int srid) { return get(new WKTReader(new GeometryFactory(new PrecisionModel(), srid)).read(s));
try { } catch (ParseException | StringIndexOutOfBoundsException | NumberFormatException ex) {
GeometryFactory geometryFactory = new GeometryFactory(new PrecisionModel(), srid);
Geometry g = new WKTReader(geometryFactory).read(s);
return get(g);
} catch (ParseException ex) {
throw DbException.convert(ex); throw DbException.convert(ex);
} }
} }
...@@ -154,8 +148,25 @@ public class ValueGeometry extends Value { ...@@ -154,8 +148,25 @@ public class ValueGeometry extends Value {
public Geometry getGeometryNoCopy() { public Geometry getGeometryNoCopy() {
if (geometry == null) { if (geometry == null) {
try { try {
int srid = 0; /*
getSRID: if (bytes.length >= 9) { * No-arg WKBReader() constructor instantiates a new GeometryFactory and a new
* PrecisionModel anyway, so special case for srid == 0 is not needed.
*/
geometry = new WKBReader(new GeometryFactory(new PrecisionModel(), getSRID())).read(bytes);
} catch (ParseException ex) {
throw DbException.convert(ex);
}
}
return geometry;
}
/**
* Return the SRID (Spatial Reference Identifier).
*
* @return spatial reference identifier
*/
public int getSRID() {
if (bytes.length >= 9) {
boolean bigEndian; boolean bigEndian;
switch (bytes[0]) { switch (bytes[0]) {
case 0: case 0:
...@@ -165,25 +176,17 @@ public class ValueGeometry extends Value { ...@@ -165,25 +176,17 @@ public class ValueGeometry extends Value {
bigEndian = false; bigEndian = false;
break; break;
default: default:
break getSRID; return 0;
} }
if ((bytes[bigEndian ? 1 : 4] & 0x20) != 0) { if ((bytes[bigEndian ? 1 : 4] & 0x20) != 0) {
srid = Bits.readInt(bytes, 5); int srid = Bits.readInt(bytes, 5);
if (!bigEndian) { if (!bigEndian) {
srid = Integer.reverseBytes(srid); srid = Integer.reverseBytes(srid);
} }
return srid;
} }
} }
/* return 0;
* No-arg WKBReader() constructor instantiates a new GeometryFactory and a new
* PrecisionModel anyway, so special case for srid == 0 is not needed.
*/
geometry = new WKBReader(new GeometryFactory(new PrecisionModel(), srid)).read(bytes);
} catch (ParseException ex) {
throw DbException.convert(ex);
}
}
return geometry;
} }
/** /**
...@@ -219,9 +222,7 @@ public class ValueGeometry extends Value { ...@@ -219,9 +222,7 @@ public class ValueGeometry extends Value {
@Override @Override
public String getSQL() { public String getSQL() {
// WKT does not hold Z or SRID with JTS 1.13. As getSQL is used to // Using bytes is faster than converting EWKB to Geometry then EWKT.
// export database, it should contains all object attributes. Moreover
// using bytes is faster than converting WKB to Geometry then to WKT.
return "X'" + StringUtils.convertBytesToHex(getBytesNoCopy()) + "'::Geometry"; return "X'" + StringUtils.convertBytesToHex(getBytesNoCopy()) + "'::Geometry";
} }
...@@ -233,7 +234,7 @@ public class ValueGeometry extends Value { ...@@ -233,7 +234,7 @@ public class ValueGeometry extends Value {
@Override @Override
public String getString() { public String getString() {
return getWKT(); return getEWKT();
} }
@Override @Override
...@@ -253,12 +254,12 @@ public class ValueGeometry extends Value { ...@@ -253,12 +254,12 @@ public class ValueGeometry extends Value {
@Override @Override
public byte[] getBytes() { public byte[] getBytes() {
return Utils.cloneByteArray(getWKB()); return Utils.cloneByteArray(getEWKB());
} }
@Override @Override
public byte[] getBytesNoCopy() { public byte[] getBytesNoCopy() {
return getWKB(); return getEWKB();
} }
@Override @Override
...@@ -269,12 +270,12 @@ public class ValueGeometry extends Value { ...@@ -269,12 +270,12 @@ public class ValueGeometry extends Value {
@Override @Override
public int getDisplaySize() { public int getDisplaySize() {
return getWKT().length(); return getEWKT().length();
} }
@Override @Override
public int getMemory() { public int getMemory() {
return getWKB().length * 20 + 24; return getEWKB().length * 20 + 24;
} }
@Override @Override
...@@ -282,24 +283,29 @@ public class ValueGeometry extends Value { ...@@ -282,24 +283,29 @@ public class ValueGeometry extends Value {
// The JTS library only does half-way support for 3D coordinates, so // The JTS library only does half-way support for 3D coordinates, so
// their equals method only checks the first two coordinates. // their equals method only checks the first two coordinates.
return other instanceof ValueGeometry && return other instanceof ValueGeometry &&
Arrays.equals(getWKB(), ((ValueGeometry) other).getWKB()); Arrays.equals(getEWKB(), ((ValueGeometry) other).getEWKB());
} }
/** /**
* Get the value in Well-Known-Text format. * Get the value in Extended Well-Known Text format.
* *
* @return the well-known-text * @return the extended well-known text
*/ */
public String getWKT() { public String getEWKT() {
return new WKTWriter(3).write(getGeometryNoCopy()); String wkt = new WKTWriter(3).write(getGeometryNoCopy());
int srid = getSRID();
return srid == 0
? wkt
// "SRID=-2147483648;".length() == 17
: new StringBuilder(wkt.length() + 17).append("SRID=").append(srid).append(';').append(wkt).toString();
} }
/** /**
* Get the value in Well-Known-Binary format. * Get the value in extended Well-Known Binary format.
* *
* @return the well-known-binary * @return the extended well-known binary
*/ */
public byte[] getWKB() { public byte[] getEWKB() {
return bytes; return bytes;
} }
......
...@@ -597,8 +597,9 @@ public class TestSpatial extends TestBase { ...@@ -597,8 +597,9 @@ public class TestSpatial extends TestBase {
* Test serialization of Z and SRID values. * Test serialization of Z and SRID values.
*/ */
private void testWKB() { private void testWKB() {
ValueGeometry geom3d = ValueGeometry.get( String ewkt = "SRID=27572;POLYGON ((67 13 6, 67 18 5, 59 18 4, 59 13 6, 67 13 6))";
"POLYGON ((67 13 6, 67 18 5, 59 18 4, 59 13 6, 67 13 6))", 27572); ValueGeometry geom3d = ValueGeometry.get(ewkt);
assertEquals(ewkt, geom3d.getString());
ValueGeometry copy = ValueGeometry.get(geom3d.getBytes()); ValueGeometry copy = ValueGeometry.get(geom3d.getBytes());
assertEquals(6, copy.getGeometry().getCoordinates()[0].z); assertEquals(6, copy.getGeometry().getCoordinates()[0].z);
assertEquals(5, copy.getGeometry().getCoordinates()[1].z); assertEquals(5, copy.getGeometry().getCoordinates()[1].z);
...@@ -606,6 +607,7 @@ public class TestSpatial extends TestBase { ...@@ -606,6 +607,7 @@ public class TestSpatial extends TestBase {
// Test SRID // Test SRID
copy = ValueGeometry.get(geom3d.getBytes()); copy = ValueGeometry.get(geom3d.getBytes());
assertEquals(27572, copy.getGeometry().getSRID()); assertEquals(27572, copy.getGeometry().getSRID());
Point point = new GeometryFactory().createPoint((new Coordinate(1.1d, 1.2d))); Point point = new GeometryFactory().createPoint((new Coordinate(1.1d, 1.2d)));
// SRID 0 // SRID 0
checkSRID(ValueGeometry.getFromGeometry(point).getBytes(), 0); checkSRID(ValueGeometry.getFromGeometry(point).getBytes(), 0);
...@@ -613,11 +615,17 @@ public class TestSpatial extends TestBase { ...@@ -613,11 +615,17 @@ public class TestSpatial extends TestBase {
checkSRID(new WKBWriter(2, ByteOrderValues.BIG_ENDIAN, true).write(point), 0); checkSRID(new WKBWriter(2, ByteOrderValues.BIG_ENDIAN, true).write(point), 0);
checkSRID(new WKBWriter(2, ByteOrderValues.LITTLE_ENDIAN, false).write(point), 0); checkSRID(new WKBWriter(2, ByteOrderValues.LITTLE_ENDIAN, false).write(point), 0);
checkSRID(new WKBWriter(2, ByteOrderValues.LITTLE_ENDIAN, true).write(point), 0); checkSRID(new WKBWriter(2, ByteOrderValues.LITTLE_ENDIAN, true).write(point), 0);
ewkt = "POINT (1.1 1.2)";
assertEquals(ewkt, ValueGeometry.getFromGeometry(point).getString());
assertEquals(ewkt, ValueGeometry.get(ewkt).getString());
// SRID 1,000,000,000 // SRID 1,000,000,000
point.setSRID(1_000_000_000); point.setSRID(1_000_000_000);
checkSRID(ValueGeometry.getFromGeometry(point).getBytes(), 1_000_000_000); checkSRID(ValueGeometry.getFromGeometry(point).getBytes(), 1_000_000_000);
checkSRID(new WKBWriter(2, ByteOrderValues.BIG_ENDIAN, true).write(point), 1_000_000_000); checkSRID(new WKBWriter(2, ByteOrderValues.BIG_ENDIAN, true).write(point), 1_000_000_000);
checkSRID(new WKBWriter(2, ByteOrderValues.LITTLE_ENDIAN, true).write(point), 1_000_000_000); checkSRID(new WKBWriter(2, ByteOrderValues.LITTLE_ENDIAN, true).write(point), 1_000_000_000);
ewkt = "SRID=1000000000;POINT (1.1 1.2)";
assertEquals(ewkt, ValueGeometry.getFromGeometry(point).getString());
assertEquals(ewkt, ValueGeometry.get(ewkt).getString());
} }
private void checkSRID(byte[] bytes, int srid) { private void checkSRID(byte[] bytes, int srid) {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论