提交 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')
GEOMETRY
","
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.
","
GEOMETRY
......
......@@ -100,31 +100,25 @@ public class ValueGeometry extends Value {
/**
* 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
*/
public static ValueGeometry get(String s) {
try {
Geometry g = new WKTReader().read(s);
return get(g);
} catch (ParseException ex) {
throw DbException.convert(ex);
}
}
/**
* Get or create a geometry value for the given geometry.
*
* @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) {
try {
GeometryFactory geometryFactory = new GeometryFactory(new PrecisionModel(), srid);
Geometry g = new WKTReader(geometryFactory).read(s);
return get(g);
} catch (ParseException ex) {
int srid;
if (s.startsWith("SRID=")) {
int idx = s.indexOf(';', 5);
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
* PrecisionModel anyway, so special case for srid == 0 is not needed.
*/
return get(new WKTReader(new GeometryFactory(new PrecisionModel(), srid)).read(s));
} catch (ParseException | StringIndexOutOfBoundsException | NumberFormatException ex) {
throw DbException.convert(ex);
}
}
......@@ -154,31 +148,11 @@ public class ValueGeometry extends Value {
public Geometry getGeometryNoCopy() {
if (geometry == null) {
try {
int srid = 0;
getSRID: if (bytes.length >= 9) {
boolean bigEndian;
switch (bytes[0]) {
case 0:
bigEndian = true;
break;
case 1:
bigEndian = false;
break;
default:
break getSRID;
}
if ((bytes[bigEndian ? 1 : 4] & 0x20) != 0) {
srid = Bits.readInt(bytes, 5);
if (!bigEndian) {
srid = Integer.reverseBytes(srid);
}
}
}
/*
* 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);
geometry = new WKBReader(new GeometryFactory(new PrecisionModel(), getSRID())).read(bytes);
} catch (ParseException ex) {
throw DbException.convert(ex);
}
......@@ -186,6 +160,35 @@ public class ValueGeometry extends Value {
return geometry;
}
/**
* Return the SRID (Spatial Reference Identifier).
*
* @return spatial reference identifier
*/
public int getSRID() {
if (bytes.length >= 9) {
boolean bigEndian;
switch (bytes[0]) {
case 0:
bigEndian = true;
break;
case 1:
bigEndian = false;
break;
default:
return 0;
}
if ((bytes[bigEndian ? 1 : 4] & 0x20) != 0) {
int srid = Bits.readInt(bytes, 5);
if (!bigEndian) {
srid = Integer.reverseBytes(srid);
}
return srid;
}
}
return 0;
}
/**
* Test if this geometry envelope intersects with the other geometry
* envelope.
......@@ -219,9 +222,7 @@ public class ValueGeometry extends Value {
@Override
public String getSQL() {
// WKT does not hold Z or SRID with JTS 1.13. As getSQL is used to
// export database, it should contains all object attributes. Moreover
// using bytes is faster than converting WKB to Geometry then to WKT.
// Using bytes is faster than converting EWKB to Geometry then EWKT.
return "X'" + StringUtils.convertBytesToHex(getBytesNoCopy()) + "'::Geometry";
}
......@@ -233,7 +234,7 @@ public class ValueGeometry extends Value {
@Override
public String getString() {
return getWKT();
return getEWKT();
}
@Override
......@@ -253,12 +254,12 @@ public class ValueGeometry extends Value {
@Override
public byte[] getBytes() {
return Utils.cloneByteArray(getWKB());
return Utils.cloneByteArray(getEWKB());
}
@Override
public byte[] getBytesNoCopy() {
return getWKB();
return getEWKB();
}
@Override
......@@ -269,12 +270,12 @@ public class ValueGeometry extends Value {
@Override
public int getDisplaySize() {
return getWKT().length();
return getEWKT().length();
}
@Override
public int getMemory() {
return getWKB().length * 20 + 24;
return getEWKB().length * 20 + 24;
}
@Override
......@@ -282,24 +283,29 @@ public class ValueGeometry extends Value {
// The JTS library only does half-way support for 3D coordinates, so
// their equals method only checks the first two coordinates.
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() {
return new WKTWriter(3).write(getGeometryNoCopy());
public String getEWKT() {
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;
}
......
......@@ -597,8 +597,9 @@ public class TestSpatial extends TestBase {
* Test serialization of Z and SRID values.
*/
private void testWKB() {
ValueGeometry geom3d = ValueGeometry.get(
"POLYGON ((67 13 6, 67 18 5, 59 18 4, 59 13 6, 67 13 6))", 27572);
String ewkt = "SRID=27572;POLYGON ((67 13 6, 67 18 5, 59 18 4, 59 13 6, 67 13 6))";
ValueGeometry geom3d = ValueGeometry.get(ewkt);
assertEquals(ewkt, geom3d.getString());
ValueGeometry copy = ValueGeometry.get(geom3d.getBytes());
assertEquals(6, copy.getGeometry().getCoordinates()[0].z);
assertEquals(5, copy.getGeometry().getCoordinates()[1].z);
......@@ -606,6 +607,7 @@ public class TestSpatial extends TestBase {
// Test SRID
copy = ValueGeometry.get(geom3d.getBytes());
assertEquals(27572, copy.getGeometry().getSRID());
Point point = new GeometryFactory().createPoint((new Coordinate(1.1d, 1.2d)));
// SRID 0
checkSRID(ValueGeometry.getFromGeometry(point).getBytes(), 0);
......@@ -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.LITTLE_ENDIAN, false).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
point.setSRID(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.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) {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论