提交 fe593d24 authored 作者: Thomas Mueller's avatar Thomas Mueller

Geometry: the returned geometry object is copied when needed.

上级 a268defe
......@@ -24,7 +24,7 @@ Change Log
</li><li>Column constraints are also visible in views (patch from Nicolas Fortin for H2GIS).
</li><li>Granting a additional right to a role that already had a right for that table was not working.
</li><li>Spatial index: a few bugs have been fixed (using spatial constraints in views,
transferring geometry objects over TCP/IP).
transferring geometry objects over TCP/IP, the returned geometry object is copied when needed).
</li><li>Issue 551: the datatype documentation was incorrect (found by Bernd Eckenfels).
</li><li>Issue 368: ON DUPLICATE KEY UPDATE did not work for multi-row inserts.
Test case from Angus Macdonald.
......
......@@ -131,7 +131,7 @@ public class SpatialTreeIndex extends BaseIndex implements SpatialIndex {
private SpatialKey getEnvelope(SearchRow row) {
Value v = row.getValue(columnIds[0]);
Geometry g = ((ValueGeometry) v.convertTo(Value.GEOMETRY)).getGeometry();
Geometry g = ((ValueGeometry) v.convertTo(Value.GEOMETRY)).getGeometryNoCopy();
Envelope env = g.getEnvelopeInternal();
return new SpatialKey(row.getKey(),
(float) env.getMinX(), (float) env.getMaxX(),
......
......@@ -168,7 +168,7 @@ public class MVSpatialIndex extends BaseIndex implements SpatialIndex, MVIndex {
return null;
}
Value v = r.getValue(columnIds[0]);
Geometry g = ((ValueGeometry) v.convertTo(Value.GEOMETRY)).getGeometry();
Geometry g = ((ValueGeometry) v.convertTo(Value.GEOMETRY)).getGeometryNoCopy();
Envelope env = g.getEnvelopeInternal();
return new SpatialKey(r.getKey(),
(float) env.getMinX(), (float) env.getMaxX(),
......@@ -222,7 +222,7 @@ public class MVSpatialIndex extends BaseIndex implements SpatialIndex, MVIndex {
private SpatialKey getEnvelope(SearchRow row) {
Value v = row.getValue(columnIds[0]);
Geometry g = ((ValueGeometry) v.convertTo(Value.GEOMETRY)).getGeometry();
Geometry g = ((ValueGeometry) v.convertTo(Value.GEOMETRY)).getGeometryNoCopy();
Envelope env = g.getEnvelopeInternal();
return new SpatialKey(row.getKey(),
(float) env.getMinX(), (float) env.getMaxX(),
......
......@@ -12,6 +12,7 @@ import java.util.Arrays;
import com.vividsolutions.jts.geom.CoordinateSequence;
import com.vividsolutions.jts.geom.CoordinateSequenceFilter;
import com.vividsolutions.jts.geom.PrecisionModel;
import org.h2.message.DbException;
import org.h2.util.StringUtils;
import com.vividsolutions.jts.geom.Envelope;
......@@ -106,6 +107,22 @@ public class ValueGeometry extends Value {
}
}
/**
* Get or create a geometry value for the given geometry.
*
* @param s the WKT representation of the geometry
* @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) {
throw DbException.convert(ex);
}
}
/**
* Get or create a geometry value for the given geometry.
*
......@@ -116,7 +133,17 @@ public class ValueGeometry extends Value {
return (ValueGeometry) Value.cache(new ValueGeometry(bytes, null));
}
/**
* Get a copy of geometry object. Geometry object is mutable. The returned
* object is therefore copied before returning.
*
* @return a copy of the geometry object
*/
public Geometry getGeometry() {
return (Geometry) getGeometryNoCopy().clone();
}
public Geometry getGeometryNoCopy() {
if (geometry == null) {
try {
geometry = new WKBReader().read(bytes);
......@@ -136,8 +163,8 @@ public class ValueGeometry extends Value {
*/
public boolean intersectsBoundingBox(ValueGeometry r) {
// the Geometry object caches the envelope
return getGeometry().getEnvelopeInternal().intersects(
r.getGeometry().getEnvelopeInternal());
return getGeometryNoCopy().getEnvelopeInternal().intersects(
r.getGeometryNoCopy().getEnvelopeInternal());
}
/**
......@@ -148,8 +175,8 @@ public class ValueGeometry extends Value {
*/
public Value getEnvelopeUnion(ValueGeometry r) {
GeometryFactory gf = new GeometryFactory();
Envelope mergedEnvelope = new Envelope(getGeometry().getEnvelopeInternal());
mergedEnvelope.expandToInclude(r.getGeometry().getEnvelopeInternal());
Envelope mergedEnvelope = new Envelope(getGeometryNoCopy().getEnvelopeInternal());
mergedEnvelope.expandToInclude(r.getGeometryNoCopy().getEnvelopeInternal());
return get(gf.toGeometry(mergedEnvelope));
}
......@@ -160,8 +187,8 @@ public class ValueGeometry extends Value {
* @return the intersection of this geometry envelope and another
*/
public ValueGeometry getEnvelopeIntersection(ValueGeometry r) {
Envelope e1 = getGeometry().getEnvelopeInternal();
Envelope e2 = r.getGeometry().getEnvelopeInternal();
Envelope e1 = getGeometryNoCopy().getEnvelopeInternal();
Envelope e2 = r.getGeometryNoCopy().getEnvelopeInternal();
Envelope e3 = e1.intersection(e2);
// try to re-use the object
if (e3 == e1) {
......@@ -188,8 +215,8 @@ public class ValueGeometry extends Value {
@Override
protected int compareSecure(Value v, CompareMode mode) {
Geometry g = ((ValueGeometry) v).getGeometry();
return getGeometry().compareTo(g);
Geometry g = ((ValueGeometry) v).getGeometryNoCopy();
return getGeometryNoCopy().compareTo(g);
}
@Override
......@@ -225,7 +252,7 @@ public class ValueGeometry extends Value {
@Override
public void set(PreparedStatement prep, int parameterIndex)
throws SQLException {
prep.setObject(parameterIndex, getGeometry());
prep.setObject(parameterIndex, getGeometryNoCopy());
}
@Override
......@@ -252,7 +279,7 @@ public class ValueGeometry extends Value {
* @return the well-known-text
*/
public String getWKT() {
return new WKTWriter().write(getGeometry());
return new WKTWriter().write(getGeometryNoCopy());
}
/**
......
......@@ -15,6 +15,8 @@ import java.sql.Types;
import java.util.Random;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.util.AffineTransformation;
import org.h2.api.Aggregate;
import org.h2.test.TestBase;
import org.h2.tools.SimpleResultSet;
......@@ -84,6 +86,7 @@ public class TestSpatial extends TestBase {
testAggregateWithGeometry();
testTableViewSpatialPredicate();
testValueGeometryScript();
testInPlaceUpdate();
}
private void testHashCode() {
......@@ -582,13 +585,12 @@ public class TestSpatial extends TestBase {
*/
private void testWKB() {
ValueGeometry geom3d = ValueGeometry.get(
"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 copy = ValueGeometry.get(geom3d.getBytes());
assertEquals(6, copy.getGeometry().getCoordinates()[0].z);
assertEquals(5, copy.getGeometry().getCoordinates()[1].z);
assertEquals(4, copy.getGeometry().getCoordinates()[2].z);
// Test SRID
geom3d.getGeometry().setSRID(27572);
copy = ValueGeometry.get(geom3d.getBytes());
assertEquals(27572, copy.getGeometry().getSRID());
}
......@@ -802,4 +804,30 @@ public class TestSpatial extends TestBase {
conn.close();
}
}
/**
* If the user mutate the geometry of the object, the object cache must not
* be updated.
*/
private void testInPlaceUpdate() throws SQLException {
Connection conn = getConnection(url);
try {
ResultSet rs = conn.createStatement().executeQuery(
"SELECT 'POINT(1 1)'::geometry");
assertTrue(rs.next());
// Mutate the geometry
((Geometry) rs.getObject(1)).apply(new AffineTransformation(1, 0,
1, 1, 0, 1));
rs.close();
rs = conn.createStatement().executeQuery(
"SELECT 'POINT(1 1)'::geometry");
assertTrue(rs.next());
// Check if the geometry is the one requested
assertEquals(1, ((Point) rs.getObject(1)).getX());
assertEquals(1, ((Point) rs.getObject(1)).getY());
rs.close();
} finally {
conn.close();
}
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论