提交 573e605d authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov

Add support of empty points to GEOMETRY data type

上级 000f7bb6
......@@ -66,9 +66,6 @@ class AggregateDataEnvelope extends AggregateData {
@Override
Value getValue(Database database, int dataType, boolean distinct) {
if (envelope == null) {
return ValueNull.INSTANCE;
}
return ValueGeometry.fromEnvelope(envelope);
}
......
......@@ -134,10 +134,11 @@ public class SpatialTreeIndex extends BaseIndex implements SpatialIndex {
return null;
}
Value v = row.getValue(columnIds[0]);
if (v == ValueNull.INSTANCE) {
double[] env;
if (v == ValueNull.INSTANCE ||
(env = ((ValueGeometry) v.convertTo(Value.GEOMETRY)).getEnvelopeNoCopy()) == null) {
return new SpatialKey(row.getKey());
}
double[] env = ((ValueGeometry) v.convertTo(Value.GEOMETRY)).getEnvelopeNoCopy();
return new SpatialKey(row.getKey(),
(float) env[MIN_X], (float) env[MAX_X], (float) env[MIN_Y], (float) env[MAX_Y]);
}
......
......@@ -274,10 +274,11 @@ public class MVSpatialIndex extends BaseIndex implements SpatialIndex, MVIndex {
private SpatialKey getKey(SearchRow row) {
Value v = row.getValue(columnIds[0]);
if (v == ValueNull.INSTANCE) {
double[] env;
if (v == ValueNull.INSTANCE ||
(env = ((ValueGeometry) v.convertTo(Value.GEOMETRY)).getEnvelopeNoCopy()) == null) {
return new SpatialKey(row.getKey());
}
double[] env = ((ValueGeometry) v.convertTo(Value.GEOMETRY)).getEnvelopeNoCopy();
return new SpatialKey(row.getKey(),
(float) env[MIN_X], (float) env[MAX_X],
(float) env[MIN_Y], (float) env[MAX_Y]);
......
......@@ -44,6 +44,8 @@ public final class EWKTUtils {
private int level;
private int type;
private boolean inMulti;
/**
......@@ -104,6 +106,7 @@ public final class EWKTUtils {
}
private void writeHeader(int type, int srid) {
this.type = type;
// Never write SRID in inner objects
if (level == 0 && srid != 0) {
output.append("SRID=").append(srid).append(';');
......@@ -177,6 +180,10 @@ public final class EWKTUtils {
@Override
protected void addCoordinate(double x, double y, double z, double m, int index, int total) {
if (type == POINT && Double.isNaN(x) && Double.isNaN(y) && Double.isNaN(z) && Double.isNaN(m)) {
output.append("EMPTY");
return;
}
if (index == 0) {
output.append('(');
} else {
......@@ -572,13 +579,17 @@ public final class EWKTUtils {
}
switch (type) {
case "POINT":
if (parentType != 0 && parentType != MULTI_POINT && parentType != GEOMETRY_COLLECTION || empty) {
if (parentType != 0 && parentType != MULTI_POINT && parentType != GEOMETRY_COLLECTION) {
throw new IllegalArgumentException();
}
empty = source.readEmpty(empty);
target.startPoint(source.srid);
source.read('(');
addCoordinate(source, target, useZ, useM, 0, 1);
source.read(')');
if (empty) {
target.addCoordinate(Double.NaN, Double.NaN, Double.NaN, Double.NaN, 0, 1);
} else {
addCoordinate(source, target, useZ, useM, 0, 1);
source.read(')');
}
break;
case "LINESTRING": {
if (parentType != 0 && parentType != MULTI_LINE_STRING && parentType != GEOMETRY_COLLECTION) {
......
......@@ -191,7 +191,7 @@ public final class GeometryUtils {
@Override
protected void addCoordinate(double x, double y, double z, double m, int index, int total) {
if (enabled) {
if (enabled && !Double.isNaN(x) && !Double.isNaN(y)) {
if (!set) {
minX = maxX = x;
minY = maxY = y;
......@@ -318,7 +318,7 @@ public final class GeometryUtils {
if (!hasM && !Double.isNaN(m)) {
hasM = true;
}
if (enabled) {
if (enabled && !Double.isNaN(x) && !Double.isNaN(y)) {
if (!set) {
minX = maxX = x;
minY = maxY = y;
......@@ -467,7 +467,7 @@ public final class GeometryUtils {
* @return envelope, or null
*/
public static double[] getEnvelope(byte[] ewkb) {
EnvelopeAndDimensionSystemTarget target = new EnvelopeAndDimensionSystemTarget();
EnvelopeTarget target = new EnvelopeTarget();
EWKBUtils.parseEWKB(ewkb, target);
return target.getEnvelope();
}
......
......@@ -149,6 +149,10 @@ public final class JTSUtils {
@Override
protected void addCoordinate(double x, double y, double z, double m, int index, int total) {
if (type == POINT && Double.isNaN(x) && Double.isNaN(y) && Double.isNaN(z) && Double.isNaN(m)) {
this.coordinates = createCoordinates(0);
return;
}
CoordinateSequence coordinates = innerOffset < 0 ? this.coordinates : innerCoordinates[innerOffset];
coordinates.setOrdinate(index, X, x);
coordinates.setOrdinate(index, Y, y);
......@@ -287,7 +291,11 @@ public final class JTSUtils {
}
target.startPoint(srid);
Point p = (Point) geometry;
addCoordinate(p.getCoordinateSequence(), target, 0, 1);
if (p.isEmpty()) {
target.addCoordinate(Double.NaN, Double.NaN, Double.NaN, Double.NaN, 0, 1);
} else {
addCoordinate(p.getCoordinateSequence(), target, 0, 1);
}
} else if (geometry instanceof LineString) {
if (parentType != 0 && parentType != MULTI_LINE_STRING && parentType != GEOMETRY_COLLECTION) {
throw new IllegalArgumentException();
......
......@@ -155,9 +155,9 @@ public class ValueGeometry extends Value {
* @param envelope envelope. May not be modified.
* @return the value
*/
public static ValueGeometry fromEnvelope(double[] envelope) {
return (ValueGeometry) Value.cache(new ValueGeometry(GeometryUtils.envelope2wkb(envelope),
GeometryUtils.DIMENSION_SYSTEM_XY, envelope));
public static Value fromEnvelope(double[] envelope) {
return envelope != null ? Value.cache(new ValueGeometry(GeometryUtils.envelope2wkb(envelope),
GeometryUtils.DIMENSION_SYSTEM_XY, envelope)): ValueNull.INSTANCE;
}
/**
......
......@@ -13,12 +13,10 @@ import java.sql.Statement;
import java.sql.Types;
import java.util.Random;
import org.h2.api.Aggregate;
import org.h2.message.DbException;
import org.h2.test.TestBase;
import org.h2.test.TestDb;
import org.h2.tools.SimpleResultSet;
import org.h2.tools.SimpleRowSource;
import org.h2.util.StringUtils;
import org.h2.value.DataType;
import org.h2.value.Value;
import org.h2.value.ValueGeometry;
......@@ -700,13 +698,6 @@ public class TestSpatial extends TestDb {
ValueGeometry valueGeometry3 = ValueGeometry.getFromGeometry(geometry);
assertEquals(valueGeometry, valueGeometry3);
assertEquals(geometry.getSRID(), ((Geometry) valueGeometry3.getGeometry()).getSRID());
// Check illegal geometry (no WKB representation)
try {
ValueGeometry.get("POINT EMPTY");
fail("expected exception");
} catch (IllegalArgumentException | DbException ex) {
// expected
}
}
/**
......
......@@ -58,6 +58,7 @@ public class TestGeometryUtils extends TestBase {
testMultiLineString();
testMultiPolygon();
testGeometryCollection();
testEmptyPoint();
testDimensionM();
testDimensionZM();
testSRID();
......@@ -144,7 +145,8 @@ public class TestGeometryUtils extends TestBase {
// Test WKB->Geometry conversion
Geometry geometryFromH2 = JTSUtils.ewkb2geometry(wkbFromJTS);
// JTS has locale-specific bugs with NaNs, also such geometries are not fully valid
// JTS has locale-specific bugs with NaNs, also such geometries are not
// fully valid
if (!wkt.contains("NaN")) {
assertEquals(jtsWkt.replaceAll(" Z", ""), new WKTWriter(numOfDimensions).write(geometryFromH2));
}
......@@ -171,18 +173,32 @@ public class TestGeometryUtils extends TestBase {
} else {
double minX = envelopeFromJTS.getMinX(), maxX = envelopeFromJTS.getMaxX();
double minY = envelopeFromJTS.getMinY(), maxY = envelopeFromJTS.getMaxY();
assertEquals(minX, envelopeFromH2[0]);
assertEquals(maxX, envelopeFromH2[1]);
assertEquals(minY, envelopeFromH2[2]);
assertEquals(maxY, envelopeFromH2[3]);
// TODO determine what to do with NaNs in dimensions X and Y
if (!Double.isNaN(minX) && !Double.isNaN(maxX) && !Double.isNaN(minY) && !Double.isNaN(maxY)) {
if (Double.isNaN(minX) || Double.isNaN(maxX) || Double.isNaN(minY) || Double.isNaN(maxY)) {
assertNull(envelopeFromH2);
assertNull(GeometryUtils.envelope2wkb(envelopeFromH2));
} else {
assertEquals(minX, envelopeFromH2[0]);
assertEquals(maxX, envelopeFromH2[1]);
assertEquals(minY, envelopeFromH2[2]);
assertEquals(maxY, envelopeFromH2[3]);
assertEquals(new WKBWriter(2).write(new GeometryFactory().toGeometry(envelopeFromJTS)),
GeometryUtils.envelope2wkb(envelopeFromH2));
}
}
}
private void testEmptyPoint() {
String ewkt = "POINT EMPTY";
byte[] ewkb = EWKTUtils.ewkt2ewkb(ewkt);
assertEquals(StringUtils.convertHexToBytes("00000000017ff80000000000007ff8000000000000"), ewkb);
assertEquals(ewkt, EWKTUtils.ewkb2ewkt(ewkb));
assertNull(GeometryUtils.getEnvelope(ewkb));
Point p = (Point) JTSUtils.ewkb2geometry(ewkb);
assertTrue(p.isEmpty());
assertEquals(ewkt, new WKTWriter().write(p));
assertEquals(ewkb, JTSUtils.geometry2ewkb(p));
}
private void testDimensionM() {
byte[] ewkb = EWKTUtils.ewkt2ewkb("POINT M (1 2 3)");
assertEquals("POINT M (1 2 3)", EWKTUtils.ewkb2ewkt(ewkb));
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论