提交 000f7bb6 authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov

Cache dimension system and envelope in ValueGeometry

上级 2ef109c3
......@@ -69,7 +69,7 @@ class AggregateDataEnvelope extends AggregateData {
if (envelope == null) {
return ValueNull.INSTANCE;
}
return ValueGeometry.get(GeometryUtils.envelope2wkb(envelope));
return ValueGeometry.fromEnvelope(envelope);
}
}
......@@ -34,7 +34,6 @@ import org.h2.result.SearchRow;
import org.h2.result.SortOrder;
import org.h2.table.IndexColumn;
import org.h2.table.TableFilter;
import org.h2.util.geometry.GeometryUtils;
import org.h2.value.Value;
import org.h2.value.ValueGeometry;
import org.h2.value.ValueLong;
......@@ -268,7 +267,7 @@ public class MVSpatialIndex extends BaseIndex implements SpatialIndex, MVIndex {
bmaxyf = maxyf;
}
}
return ValueGeometry.get(GeometryUtils.envelope2wkb(new double[] {bminxf, bmaxxf, bminyf, bmaxyf}));
return ValueGeometry.fromEnvelope(new double[] {bminxf, bmaxxf, bminyf, bmaxyf});
}
return ValueNull.INSTANCE;
}
......@@ -514,8 +513,7 @@ public class MVSpatialIndex extends BaseIndex implements SpatialIndex, MVIndex {
}
Value getBounds() {
return hasBounds ? ValueGeometry.get(
GeometryUtils.envelope2wkb(new double[] {bminxd, bmaxxd, bminyd, bmaxyd}))
return hasBounds ? ValueGeometry.fromEnvelope(new double[] {bminxd, bmaxxd, bminyd, bmaxyd})
: ValueNull.INSTANCE;
}
......
......@@ -237,11 +237,26 @@ public final class EWKBUtils {
public static byte[] ewkb2ewkb(byte[] ewkb) {
// Determine dimension system first
DimensionSystemTarget dimensionTarget = new DimensionSystemTarget();
parseEKWB(ewkb, dimensionTarget);
parseEWKB(ewkb, dimensionTarget);
// Write an EWKB
return ewkb2ewkb(ewkb, dimensionTarget.getDimensionSystem());
}
/**
* Converts any supported EWKB to EWKB representation that is used by this
* class. Reduces dimension system to minimal possible and uses EWKB flags
* for dimension system indication. May also perform other changes.
*
* @param ewkb
* source EWKB
* @param dimension
* dimension system
* @return canonical EWKB, may be the same as the source
*/
public static byte[] ewkb2ewkb(byte[] ewkb, int dimensionSystem) {
ByteArrayOutputStream output = new ByteArrayOutputStream();
EWKBTarget target = new EWKBTarget(output, dimensionTarget.getDimensionSystem());
parseEKWB(ewkb, target);
EWKBTarget target = new EWKBTarget(output, dimensionSystem);
parseEWKB(ewkb, target);
return output.toByteArray();
}
......@@ -253,8 +268,8 @@ public final class EWKBUtils {
* @param target
* output target
*/
public static void parseEKWB(byte[] ewkb, Target target) {
parseEKWB(new EWKBSource(ewkb), target, 0, 0);
public static void parseEWKB(byte[] ewkb, Target target) {
parseEWKB(new EWKBSource(ewkb), target, 0, 0);
}
/**
......@@ -270,7 +285,7 @@ public final class EWKBUtils {
* SRID of a parent geometry collection, or any value for the
* root geometry (will be determined from the EWKB instead)
*/
private static void parseEKWB(EWKBSource source, Target target, int parentType, int parentSrid) {
private static void parseEWKB(EWKBSource source, Target target, int parentType, int parentSrid) {
try {
// Read byte order of a next geometry
switch (source.readByte()) {
......@@ -374,7 +389,7 @@ public final class EWKBUtils {
target.startCollection(type, srid, numItems);
for (int i = 0; i < numItems; i++) {
Target innerTarget = target.startCollectionItem(i, numItems);
parseEKWB(source, innerTarget, type, srid);
parseEWKB(source, innerTarget, type, srid);
target.endCollectionItem(innerTarget, i, numItems);
}
target.endCollection(type);
......
......@@ -442,11 +442,24 @@ public final class EWKTUtils {
public static String ewkb2ewkt(byte[] ewkb) {
// Determine dimension system first
DimensionSystemTarget dimensionTarget = new DimensionSystemTarget();
EWKBUtils.parseEKWB(ewkb, dimensionTarget);
EWKBUtils.parseEWKB(ewkb, dimensionTarget);
// Write an EWKT
return ewkb2ewkt(ewkb, dimensionTarget.getDimensionSystem());
}
/**
* Converts EWKB to EWKT.
*
* @param ewkb
* source EWKB
* @param dimension
* dimension system
* @return EWKT representation
*/
public static String ewkb2ewkt(byte[] ewkb, int dimensionSystem) {
StringBuilder output = new StringBuilder();
EWKTTarget target = new EWKTTarget(output, dimensionTarget.getDimensionSystem());
EWKBUtils.parseEKWB(ewkb, target);
EWKTTarget target = new EWKTTarget(output, dimensionSystem);
EWKBUtils.parseEWKB(ewkb, target);
return output.toString();
}
......@@ -462,8 +475,21 @@ public final class EWKTUtils {
DimensionSystemTarget dimensionTarget = new DimensionSystemTarget();
parseEWKT(ewkt, dimensionTarget);
// Write an EWKB
return ewkt2ewkb(ewkt, dimensionTarget.getDimensionSystem());
}
/**
* Converts EWKT to EWKB.
*
* @param ewkt
* source EWKT
* @param dimension
* dimension system
* @return EWKB representation
*/
public static byte[] ewkt2ewkb(String ewkt, int dimensionSystem) {
ByteArrayOutputStream output = new ByteArrayOutputStream();
EWKBTarget target = new EWKBTarget(output, dimensionTarget.getDimensionSystem());
EWKBTarget target = new EWKBTarget(output, dimensionSystem);
parseEWKT(ewkt, target);
return output.toByteArray();
}
......
......@@ -468,7 +468,7 @@ public final class GeometryUtils {
*/
public static double[] getEnvelope(byte[] ewkb) {
EnvelopeAndDimensionSystemTarget target = new EnvelopeAndDimensionSystemTarget();
EWKBUtils.parseEKWB(ewkb, target);
EWKBUtils.parseEWKB(ewkb, target);
return target.getEnvelope();
}
......
......@@ -198,10 +198,23 @@ public final class JTSUtils {
public static Geometry ewkb2geometry(byte[] ewkb) {
// Determine dimension system first
DimensionSystemTarget dimensionTarget = new DimensionSystemTarget();
EWKBUtils.parseEKWB(ewkb, dimensionTarget);
EWKBUtils.parseEWKB(ewkb, dimensionTarget);
// Generate a Geometry
GeometryTarget target = new GeometryTarget(dimensionTarget.getDimensionSystem());
EWKBUtils.parseEKWB(ewkb, target);
return ewkb2geometry(ewkb, dimensionTarget.getDimensionSystem());
}
/**
* Converts EWKB to a JTS geometry object.
*
* @param ewkb
* source EWKB
* @param dimensionSystem
* dimension system
* @return JTS geometry object
*/
public static Geometry ewkb2geometry(byte[] ewkb, int dimensionSystem) {
GeometryTarget target = new GeometryTarget(dimensionSystem);
EWKBUtils.parseEWKB(ewkb, target);
return target.getGeometry();
}
......@@ -216,9 +229,23 @@ public final class JTSUtils {
// Determine dimension system first
DimensionSystemTarget dimensionTarget = new DimensionSystemTarget();
parseGeometry(geometry, dimensionTarget);
// Write an EWKB
return geometry2ewkb(geometry, dimensionTarget.getDimensionSystem());
}
/**
* Converts Geometry to EWKB.
*
* @param geometry
* source geometry
* @param dimensionSystem
* dimension system
* @return EWKB representation
*/
public static byte[] geometry2ewkb(Geometry geometry, int dimensionSystem) {
// Write an EWKB
ByteArrayOutputStream output = new ByteArrayOutputStream();
EWKBTarget target = new EWKBTarget(output, dimensionTarget.getDimensionSystem());
EWKBTarget target = new EWKBTarget(output, dimensionSystem);
parseGeometry(geometry, target);
return output.toByteArray();
}
......@@ -231,7 +258,7 @@ public final class JTSUtils {
* @param target
* output target
*/
private static void parseGeometry(Geometry geometry, Target target) {
public static void parseGeometry(Geometry geometry, Target target) {
parseGeometry(geometry, target, 0, 0);
}
......
......@@ -1215,7 +1215,7 @@ public abstract class Value {
private ValueGeometry convertToGeometry() {
switch (getType()) {
case BYTES:
return ValueGeometry.get(getBytesNoCopy());
return ValueGeometry.getFromEWKB(getBytesNoCopy());
case JAVA_OBJECT:
Object object = JdbcUtils.deserialize(getBytesNoCopy(), getDataHandler());
if (DataType.isGeometry(object)) {
......
......@@ -13,8 +13,10 @@ import org.h2.message.DbException;
import org.h2.util.Bits;
import org.h2.util.StringUtils;
import org.h2.util.Utils;
import org.h2.util.geometry.EWKBUtils;
import org.h2.util.geometry.EWKTUtils;
import org.h2.util.geometry.GeometryUtils;
import org.h2.util.geometry.GeometryUtils.EnvelopeAndDimensionSystemTarget;
import org.h2.util.geometry.JTSUtils;
import org.locationtech.jts.geom.Geometry;
......@@ -40,10 +42,9 @@ public class ValueGeometry extends Value {
private final int hashCode;
/**
* The value. Converted from WKB only on request as conversion from/to WKB
* cost a significant amount of CPU cycles.
* Dimension system. -1 if not known yet.
*/
private Object geometry;
private int dimensionSystem;
/**
* The envelope of the value. Calculated only on request.
......@@ -51,13 +52,23 @@ public class ValueGeometry extends Value {
private double[] envelope;
/**
* Create a new geometry objects.
* The value. Converted from WKB only on request as conversion from/to WKB
* cost a significant amount of CPU cycles.
*/
private Object geometry;
/**
* Create a new geometry object.
*
* @param bytes the EWKB bytes
* @param dimensionSystem dimension system
* @param envelope the envelope
*/
private ValueGeometry(byte[] bytes) {
private ValueGeometry(byte[] bytes, int dimensionSystem, double[] envelope) {
this.bytes = bytes;
this.hashCode = Arrays.hashCode(bytes);
this.dimensionSystem = dimensionSystem;
this.envelope = envelope;
}
/**
......@@ -68,7 +79,16 @@ public class ValueGeometry extends Value {
* @return the value
*/
public static ValueGeometry getFromGeometry(Object o) {
return get(JTSUtils.geometry2ewkb((Geometry) o));
try {
EnvelopeAndDimensionSystemTarget target = new EnvelopeAndDimensionSystemTarget();
Geometry g = (Geometry) o;
JTSUtils.parseGeometry(g, target);
int dimensionSystem = target.getDimensionSystem();
return (ValueGeometry) Value.cache(new ValueGeometry(JTSUtils.geometry2ewkb(g, dimensionSystem),
dimensionSystem, target.getEnvelope()));
} catch (RuntimeException ex) {
throw DbException.convert(ex);
}
}
/**
......@@ -79,7 +99,11 @@ public class ValueGeometry extends Value {
*/
public static ValueGeometry get(String s) {
try {
return get(EWKTUtils.ewkt2ewkb(s));
EnvelopeAndDimensionSystemTarget target = new EnvelopeAndDimensionSystemTarget();
EWKTUtils.parseEWKT(s, target);
int dimensionSystem = target.getDimensionSystem();
return (ValueGeometry) Value.cache(new ValueGeometry(EWKTUtils.ewkt2ewkb(s, dimensionSystem),
dimensionSystem, target.getEnvelope()));
} catch (RuntimeException ex) {
throw DbException.convert(ex);
}
......@@ -98,13 +122,42 @@ public class ValueGeometry extends Value {
}
/**
* Get or create a geometry value for the given geometry.
* Get or create a geometry value for the given internal EWKB representation.
*
* @param bytes the WKB representation of the geometry
* @param bytes the WKB representation of the geometry. May not be modified.
* @return the value
*/
public static ValueGeometry get(byte[] bytes) {
return (ValueGeometry) Value.cache(new ValueGeometry(bytes));
return (ValueGeometry) Value.cache(new ValueGeometry(bytes, -1, null));
}
/**
* Get or create a geometry value for the given EWKB value.
*
* @param bytes the WKB representation of the geometry
* @return the value
*/
public static ValueGeometry getFromEWKB(byte[] bytes) {
try {
EnvelopeAndDimensionSystemTarget target = new EnvelopeAndDimensionSystemTarget();
EWKBUtils.parseEWKB(bytes, target);
int dimensionSystem = target.getDimensionSystem();
return (ValueGeometry) Value.cache(new ValueGeometry(EWKBUtils.ewkb2ewkb(bytes, dimensionSystem),
dimensionSystem, target.getEnvelope()));
} catch (RuntimeException ex) {
throw DbException.convert(ex);
}
}
/**
* Creates a geometry value for the given envelope.
*
* @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));
}
/**
......@@ -116,7 +169,7 @@ public class ValueGeometry extends Value {
public Object getGeometry() {
if (geometry == null) {
try {
geometry = JTSUtils.ewkb2geometry(bytes);
geometry = JTSUtils.ewkb2geometry(bytes, getDimensionSystem());
} catch (RuntimeException ex) {
throw DbException.convert(ex);
}
......@@ -153,15 +206,32 @@ public class ValueGeometry extends Value {
return 0;
}
private void calculateInfo() {
if (dimensionSystem < 0) {
EnvelopeAndDimensionSystemTarget target = new EnvelopeAndDimensionSystemTarget();
EWKBUtils.parseEWKB(bytes, target);
envelope = target.getEnvelope();
dimensionSystem = target.getDimensionSystem();
}
}
/**
* Return a minimal dimension system that can be used for this geometry.
*
* @return dimension system
*/
public int getDimensionSystem() {
calculateInfo();
return dimensionSystem;
}
/**
* Return an envelope of this geometry. Do not modify the returned value.
*
* @return envelope of this geometry
*/
public double[] getEnvelopeNoCopy() {
if (envelope == null) {
envelope = GeometryUtils.getEnvelope(bytes);
}
calculateInfo();
return envelope;
}
......@@ -183,7 +253,7 @@ public class ValueGeometry extends Value {
* @return the union of this geometry envelope and another geometry envelope
*/
public Value getEnvelopeUnion(ValueGeometry r) {
return get(GeometryUtils.envelope2wkb(GeometryUtils.union(getEnvelopeNoCopy(), r.getEnvelopeNoCopy())));
return fromEnvelope(GeometryUtils.union(getEnvelopeNoCopy(), r.getEnvelopeNoCopy()));
}
@Override
......@@ -247,12 +317,12 @@ public class ValueGeometry extends Value {
@Override
public int getMemory() {
return getEWKB().length * 20 + 24;
return bytes.length * 20 + 24;
}
@Override
public boolean equals(Object other) {
return other instanceof ValueGeometry && Arrays.equals(getEWKB(), ((ValueGeometry) other).getEWKB());
return other instanceof ValueGeometry && Arrays.equals(bytes, ((ValueGeometry) other).bytes);
}
/**
......@@ -261,7 +331,7 @@ public class ValueGeometry extends Value {
* @return the extended well-known text
*/
public String getEWKT() {
return EWKTUtils.ewkb2ewkt(bytes);
return EWKTUtils.ewkb2ewkt(bytes, getDimensionSystem());
}
/**
......
......@@ -156,7 +156,7 @@ public class TestGeometryUtils extends TestBase {
Envelope envelopeFromJTS = geometryFromJTS.getEnvelopeInternal();
testEnvelope(envelopeFromJTS, GeometryUtils.getEnvelope(wkbFromJTS));
EnvelopeAndDimensionSystemTarget target = new EnvelopeAndDimensionSystemTarget();
EWKBUtils.parseEKWB(wkbFromJTS, target);
EWKBUtils.parseEWKB(wkbFromJTS, target);
testEnvelope(envelopeFromJTS, target.getEnvelope());
// Test dimensions
......@@ -242,10 +242,10 @@ public class TestGeometryUtils extends TestBase {
private void testDimensions(int expected, byte[] ewkb) {
DimensionSystemTarget dst = new DimensionSystemTarget();
EWKBUtils.parseEKWB(ewkb, dst);
EWKBUtils.parseEWKB(ewkb, dst);
assertEquals(expected, dst.getDimensionSystem());
EnvelopeAndDimensionSystemTarget envelopeAndDimensionTarget = new EnvelopeAndDimensionSystemTarget();
EWKBUtils.parseEKWB(ewkb, envelopeAndDimensionTarget);
EWKBUtils.parseEWKB(ewkb, envelopeAndDimensionTarget);
assertEquals(expected, envelopeAndDimensionTarget.getDimensionSystem());
}
......
......@@ -793,4 +793,4 @@ immediate hhmmss scheduled hhmm prematurely postponed arranges subexpression sub
minxf maxxf minyf maxyf bminxf bmaxxf bminyf bmaxyf
minxd maxxd minyd maxyd bminxd bmaxxd bminyd bmaxyd
interior envelopes multilinestring multipoint packed exterior normalization awkward determination subgeometries
xym ekwb normalizes coord setz xyzm geometrycollection multipolygon mixup rings polygons
xym normalizes coord setz xyzm geometrycollection multipolygon mixup rings polygons
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论