From c9f27779dd4ce16120cb892e2744fcf5cbced4f1 Mon Sep 17 00:00:00 2001 From: Karel Maesen Date: Tue, 30 Oct 2012 22:17:59 +0100 Subject: [PATCH] HHH-6511 - Uses Geolatte-Geom WKB encoder/decoder for Postgis dialect. HHH-7126 - Uses Geolatte-Geom WKB encoder/decoder for GeoDB dialect. --- .../postgis/jdbc/postgis-jdbc-1.5.2.jar | Bin 87341 -> 0 bytes .../postgis/resources/hibernate.properties | 1 + hibernate-spatial/hibernate-spatial.gradle | 14 +- .../h2geodb/GeoDBGeometryTypeDescriptor.java | 45 ++- .../dialect/h2geodb/GeoDBValueBinder.java | 58 ---- .../dialect/h2geodb/GeoDBValueExtractor.java | 164 ---------- .../spatial/dialect/h2geodb/GeoDbWkb.java | 136 ++++++++ .../spatial/dialect/h2geodb/WKB.java | 68 ---- .../mysql/MySQLGeometryTypeDescriptor.java | 60 +++- .../mysql/MySQLGeometryValueBinder.java | 103 ------ .../mysql/MySQLGeometryValueExtractor.java | 75 ----- .../postgis/PGGeometryTypeDescriptor.java | 60 +++- .../postgis/PGGeometryValueBinder.java | 293 ------------------ .../postgis/PGGeometryValueExtractor.java | 284 ----------------- .../sqlserver/convertors/AbstractEncoder.java | 2 +- .../CountingPointSequenceBuilder.java | 12 +- .../convertors/LineStringDecoder.java | 3 +- .../sqlserver/convertors/PointDecoder.java | 3 +- .../sqlserver/convertors/PolygonDecoder.java | 3 +- .../convertors/SqlServerGeometry.java | 53 ++-- .../convertors/LineStringConvertorTest.java | 13 +- .../convertors/PointConvertorTest.java | 8 +- .../spatial/integration/GeomEntity.java | 5 +- .../spatial/testing/DataSourceUtils.java | 30 +- .../spatial/testing/TestDataElement.java | 4 +- .../spatial/testing/TestDataReader.java | 3 +- .../hibernate/spatial/testing/WktUtility.java | 30 ++ .../h2geodb/GeoDBExpectationsFactory.java | 86 +---- .../h2geodb/GeoDBExpressionTemplate.java | 11 +- .../GeoDBNoSRIDExpectationsFactory.java | 194 +----------- .../mysql/MySQLExpectationsFactory.java | 17 +- .../mysql/MySQLExpressionTemplate.java | 7 +- .../dialects/mysql/MySQLTestSupport.java | 7 +- .../dialects/oracle/SDOTestDataElement.java | 4 +- .../dialects/oracle/SDOTestDataReader.java | 3 +- .../postgis/PostgisExpectationsFactory.java | 27 +- .../postgis/PostgisExpressionTemplate.java | 5 +- .../SQLServerExpressionTemplate.java | 7 +- .../resources/h2geodb/test-geodb-data-set.xml | 27 +- .../src/test/resources/hibernate.properties | 32 +- .../mysql/test-mysql-functions-data-set.xml | 57 ++-- .../test-sdo-geometry-data-set-2D.xml | 30 +- .../oracle10g/test-sdo-geometry-data-set.xml | 78 ++--- .../test/resources/postgis-functions-test.xml | 33 +- .../src/test/resources/test-data-set.xml | 116 +++---- 45 files changed, 600 insertions(+), 1671 deletions(-) delete mode 100644 hibernate-spatial/databases/postgis/jdbc/postgis-jdbc-1.5.2.jar delete mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/h2geodb/GeoDBValueBinder.java delete mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/h2geodb/GeoDBValueExtractor.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/h2geodb/GeoDbWkb.java delete mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/h2geodb/WKB.java delete mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/mysql/MySQLGeometryValueBinder.java delete mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/mysql/MySQLGeometryValueExtractor.java delete mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PGGeometryValueBinder.java delete mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PGGeometryValueExtractor.java create mode 100644 hibernate-spatial/src/test/java/org/hibernate/spatial/testing/WktUtility.java diff --git a/hibernate-spatial/databases/postgis/jdbc/postgis-jdbc-1.5.2.jar b/hibernate-spatial/databases/postgis/jdbc/postgis-jdbc-1.5.2.jar deleted file mode 100644 index 5c063f65e6ab52dc1da0cb9ee2eb7d915c55796f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 87341 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 ValueBinder getBinder(JavaTypeDescriptor javaTypeDescriptor) { - return (ValueBinder) new GeoDBValueBinder(javaTypeDescriptor); + public ValueBinder getBinder(final JavaTypeDescriptor javaTypeDescriptor) { + return new BasicBinder( javaTypeDescriptor, this ) { + @Override + protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) + throws SQLException { + Geometry geometry = getJavaDescriptor().unwrap( value, Geometry.class, options ); + st.setBytes( index, GeoDbWkb.to( geometry ) ); + } + }; } @Override - public ValueExtractor getExtractor(JavaTypeDescriptor javaTypeDescriptor) { - return (ValueExtractor) new GeoDBValueExtractor(javaTypeDescriptor); + public ValueExtractor getExtractor(final JavaTypeDescriptor javaTypeDescriptor) { + return new BasicExtractor( javaTypeDescriptor, this ) { + + @Override + protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException { + return getJavaDescriptor().wrap( GeoDbWkb.from( rs.getObject( name ) ), options ); + } + + @Override + protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException { + return getJavaDescriptor().wrap( GeoDbWkb.from( statement.getObject( index ) ), options ); + } + + @Override + protected X doExtract(CallableStatement statement, String name, WrapperOptions options) + throws SQLException { + return getJavaDescriptor().wrap( GeoDbWkb.from( statement.getObject( name ) ), options ); + } + }; } + + + } diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/h2geodb/GeoDBValueBinder.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/h2geodb/GeoDBValueBinder.java deleted file mode 100644 index c981d7a7aa..0000000000 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/h2geodb/GeoDBValueBinder.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * This file is part of Hibernate Spatial, an extension to the - * hibernate ORM solution for spatial (geographic) data. - * - * Copyright © 2007-2012 Geovise BVBA, Geodan IT b.v. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -package org.hibernate.spatial.dialect.h2geodb; - -import java.sql.Connection; - -import com.vividsolutions.jts.geom.Geometry; - -import org.hibernate.spatial.Log; -import org.hibernate.spatial.LogFactory; -import org.hibernate.spatial.dialect.AbstractGeometryValueBinder; -import org.hibernate.type.descriptor.java.JavaTypeDescriptor; - -/** - * @author Jan Boonen, Geodan IT b.v. - * @author Karel Maesen, Geovise BVBA - * creation-date: 2/29/12 - */ -public class GeoDBValueBinder extends AbstractGeometryValueBinder { - - private static Log LOG = LogFactory.make(); - - public GeoDBValueBinder(JavaTypeDescriptor javaDescriptor) { - super( javaDescriptor, GeoDBGeometryTypeDescriptor.INSTANCE ); - } - - @Override - protected Object toNative(Geometry jtsGeom, Connection connection) { - try { - return WKB.toWKB( jtsGeom ); - } - catch ( Exception e ) { - LOG.warn( "Could not convert JTS Geometry to a database object." ); - e.printStackTrace(); - return null; - } - } - -} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/h2geodb/GeoDBValueExtractor.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/h2geodb/GeoDBValueExtractor.java deleted file mode 100644 index c922b1e8f5..0000000000 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/h2geodb/GeoDBValueExtractor.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * This file is part of Hibernate Spatial, an extension to the - * hibernate ORM solution for spatial (geographic) data. - * - * Copyright © 2007-2012 Geovise BVBA, Geodan IT b.v. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -package org.hibernate.spatial.dialect.h2geodb; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.sql.Blob; - -import com.vividsolutions.jts.geom.Envelope; -import com.vividsolutions.jts.geom.Geometry; -import com.vividsolutions.jts.io.ParseException; -import com.vividsolutions.jts.io.WKBConstants; - -import org.hibernate.HibernateException; -import org.hibernate.spatial.Log; -import org.hibernate.spatial.LogFactory; -import org.hibernate.spatial.dialect.AbstractGeometryValueExtractor; -import org.hibernate.type.descriptor.java.JavaTypeDescriptor; - -/** - * @author Karel Maesen, Geovise BVBA - * creation-date: 2/29/12 - */ -public class GeoDBValueExtractor extends AbstractGeometryValueExtractor { - - private static Log LOG = LogFactory.make(); - - public GeoDBValueExtractor(JavaTypeDescriptor javaDescriptor) { - super( javaDescriptor, GeoDBGeometryTypeDescriptor.INSTANCE ); - } - - @Override - public Geometry toJTS(Object object) { - if ( object == null ) { - return null; - } - try { - if ( object instanceof Blob ) { - return WKB.fromWKB( toByteArray( (Blob) object ), getGeometryFactory() ); - } - else if ( object instanceof byte[] ) { - return geometryFromByteArray( (byte[]) object ); - } - else if ( object instanceof Envelope ) { - return getGeometryFactory().toGeometry( (Envelope) object ); - } - else { - throw new IllegalArgumentException( - "Can't convert database object of type " - + object.getClass().getCanonicalName() - ); - } - } - catch ( Exception e ) { - LOG.warn( "Could not convert database object to a JTS Geometry." ); - throw new HibernateException( e ); - } - } - - - /** - * Convert a WKB or EWKB byte array to a {@link Geometry}. To figure out - * whether the byte array is either a WKB or EWK the following checks are - * performed:
- *
    - *
  1. If the first byte is not 0 or 1, the geometry must be an EWKB (with - * the first 32 bytes as a bounding box)
  2. - *
  3. Otherwise, the the byte array is parsed as a WKB
  4. - *
  5. When a parse error occurs it is assumed that the byte array is a EWKB - * (with the first byte accidentally a 0 or 1), and parsed as EWKB
  6. - *
- * - * @param bytes - * - * @return - */ - private Geometry geometryFromByteArray(byte[] bytes) throws ParseException { - /* - * wkbXDR = 0, // Big Endian - * wkbNDR = 1 // Little Endian - */ - if ( bytes[0] != WKBConstants.wkbNDR && bytes[0] != WKBConstants.wkbXDR ) { - // process as EWKB - return WKB.fromEWKB( bytes, getGeometryFactory() ); - } - else { - // process as WKB - try { - return WKB.fromWKB( bytes, getGeometryFactory() ); - } - catch ( RuntimeException e ) { - // note: ParseException is wrapped in a RuntimeException in - // geodb.GeoDB - if ( e.getCause() != null - && e.getCause() instanceof ParseException ) { - // retry as EWKB, this should rarely happen, but may occur - // when the first byte of the EWKB bounding-box is '0'. - // this should not be considered as a error - LOG.debug( - "Caught parse exception while parsing byte array as WKB. Retrying as EWKB.", - e - ); - return WKB.fromEWKB( bytes, getGeometryFactory() ); - } - else { - // this is an other exception, simply re-throw - throw e; - } - } - } - } - - private byte[] toByteArray(Blob blob) { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - byte[] buf = new byte[1024]; - - InputStream in = null; - try { - in = blob.getBinaryStream(); - int n = 0; - while ( ( n = in.read( buf ) ) >= 0 ) { - baos.write( buf, 0, n ); - - } - } - catch ( Exception e ) { - LOG.warn( "Could not convert database BLOB object to binary stream.", e ); - } - finally { - try { - if ( in != null ) { - in.close(); - } - } - catch ( IOException e ) { - LOG.warn( "Could not close binary stream." ); - } - } - - return baos.toByteArray(); - } - - -} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/h2geodb/GeoDbWkb.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/h2geodb/GeoDbWkb.java new file mode 100644 index 0000000000..b3acddd467 --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/h2geodb/GeoDbWkb.java @@ -0,0 +1,136 @@ +/* + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for spatial (geographic) data. + * + * Copyright © 2007-2012 Geovise BVBA, Geodan IT b.v. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +package org.hibernate.spatial.dialect.h2geodb; + + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.sql.Blob; + +import org.geolatte.geom.ByteBuffer; +import org.geolatte.geom.ByteOrder; +import org.geolatte.geom.DimensionalFlag; +import org.geolatte.geom.Envelope; +import org.geolatte.geom.Geometry; +import org.geolatte.geom.PointSequence; +import org.geolatte.geom.PointSequenceBuilders; +import org.geolatte.geom.Polygon; +import org.geolatte.geom.codec.Wkb; +import org.geolatte.geom.codec.WkbDecoder; +import org.geolatte.geom.codec.WkbEncoder; +import org.geolatte.geom.crs.CrsId; +import org.geolatte.geom.jts.JTS; + +import org.hibernate.HibernateException; +import org.hibernate.spatial.Log; +import org.hibernate.spatial.LogFactory; + +/** + * A utility class to serialize from/to GeoDB WKB's. + *

+ *

Note: this utility makes it unnecessary to have a dependency on GeoDB. As long as GeoDB is + * not available in common maven repositories, such a dependency is to be avoided.

+ * + * @author Karel Maesen, Geovise BVBA + * creation-date: 2/29/12 + */ +public class GeoDbWkb { + + private static Log LOG = LogFactory.make(); + + + public static byte[] to(Geometry geometry) { + WkbEncoder encoder = Wkb.newEncoder( Wkb.Dialect.POSTGIS_EWKB_1 ); + ByteBuffer buffer = encoder.encode( geometry, ByteOrder.NDR ); + return ( buffer == null ? null : buffer.toByteArray() ); + } + + public static Geometry from(Object object) { + if ( object == null ) { + return null; + } + try { + WkbDecoder decoder = Wkb.newDecoder( Wkb.Dialect.POSTGIS_EWKB_1 ); + if ( object instanceof Blob ) { + return decoder.decode( toByteBuffer( (Blob) object ) ); + } + else if ( object instanceof byte[] ) { + return decoder.decode( ByteBuffer.from( (byte[]) object ) ); + } + else if ( object instanceof com.vividsolutions.jts.geom.Envelope ) { + return toPolygon( JTS.from( (com.vividsolutions.jts.geom.Envelope) object ) ); + } + else { + throw new IllegalArgumentException( + "Can't convert database object of type " + + object.getClass().getCanonicalName() + ); + } + } + catch ( Exception e ) { + LOG.warn( "Could not convert database object to a Geometry." ); + throw new HibernateException( e ); + } + + } + + private static Geometry toPolygon(Envelope env) { + PointSequence ps = PointSequenceBuilders.fixedSized( 4, DimensionalFlag.d2D, CrsId.UNDEFINED ) + .add( env.getMinX(), env.getMinY() ) + .add( env.getMinX(), env.getMaxY() ) + .add( env.getMaxX(), env.getMaxY() ) + .add( env.getMinX(), env.getMinY() ).toPointSequence(); + return new Polygon( ps ); + } + + private static ByteBuffer toByteBuffer(Blob blob) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte[] buf = new byte[1024]; + + InputStream in = null; + try { + in = blob.getBinaryStream(); + int n = 0; + while ( ( n = in.read( buf ) ) >= 0 ) { + baos.write( buf, 0, n ); + } + } + catch ( Exception e ) { + LOG.warn( "Could not convert database BLOB object to binary stream.", e ); + } + finally { + try { + if ( in != null ) { + in.close(); + } + } + catch ( IOException e ) { + LOG.warn( "Could not close binary stream." ); + } + } + return ByteBuffer.from( baos.toByteArray() ); + } + + +} + diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/h2geodb/WKB.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/h2geodb/WKB.java deleted file mode 100644 index a87104358d..0000000000 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/h2geodb/WKB.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * This file is part of Hibernate Spatial, an extension to the - * hibernate ORM solution for spatial (geographic) data. - * - * Copyright © 2007-2012 Geovise BVBA, Geodan IT b.v. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -package org.hibernate.spatial.dialect.h2geodb; - -import com.vividsolutions.jts.geom.Geometry; -import com.vividsolutions.jts.geom.GeometryFactory; -import com.vividsolutions.jts.io.ParseException; -import com.vividsolutions.jts.io.WKBReader; -import com.vividsolutions.jts.io.WKBWriter; - -/** - * A utility class to serialize from/to GeoDB WKB's. - *

- *

Note: this utility makes it unnecessary to have a dependency on GeoDB. As long as GeoDB is - * not available in common maven repositories, such a dependency is to be avoided.

- * - * @author Karel Maesen, Geovise BVBA - * creation-date: 2/29/12 - */ -class WKB { - - static Geometry fromWKB(byte[] bytes, GeometryFactory factory) throws ParseException { - WKBReader reader = new WKBReader( factory ); - return reader.read( bytes ); - } - - /** - * Reads a EWKB byte (which is just a WKB prepended with an envelope of 32 bytes. - * - * @param bytes - * @param factory - * - * @return - * - * @throws ParseException - */ - static Geometry fromEWKB(byte[] bytes, GeometryFactory factory) throws ParseException { - byte[] wkbBytes = new byte[bytes.length - 32]; - System.arraycopy( bytes, 32, wkbBytes, 0, bytes.length - 32 ); - return fromWKB( wkbBytes, factory ); - } - - - static byte[] toWKB(Geometry jtsGeom) { - WKBWriter writer = new WKBWriter( 2, true ); - return writer.write( jtsGeom ); - } -} - diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/mysql/MySQLGeometryTypeDescriptor.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/mysql/MySQLGeometryTypeDescriptor.java index 939705234a..b9e27bfe22 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/mysql/MySQLGeometryTypeDescriptor.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/mysql/MySQLGeometryTypeDescriptor.java @@ -21,12 +21,26 @@ package org.hibernate.spatial.dialect.mysql; +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; import java.sql.Types; +import org.geolatte.geom.ByteBuffer; +import org.geolatte.geom.ByteOrder; +import org.geolatte.geom.Geometry; +import org.geolatte.geom.codec.Wkb; +import org.geolatte.geom.codec.WkbDecoder; +import org.geolatte.geom.codec.WkbEncoder; + import org.hibernate.spatial.GeometrySqlTypeDescriptor; import org.hibernate.type.descriptor.ValueBinder; import org.hibernate.type.descriptor.ValueExtractor; +import org.hibernate.type.descriptor.WrapperOptions; import org.hibernate.type.descriptor.java.JavaTypeDescriptor; +import org.hibernate.type.descriptor.sql.BasicBinder; +import org.hibernate.type.descriptor.sql.BasicExtractor; /** * @author Karel Maesen, Geovise BVBA @@ -51,13 +65,51 @@ public class MySQLGeometryTypeDescriptor extends GeometrySqlTypeDescriptor { return false; } + @Override - public ValueBinder getBinder(JavaTypeDescriptor javaTypeDescriptor) { - return (ValueBinder) new MySQLGeometryValueBinder(javaTypeDescriptor); + public ValueBinder getBinder(final JavaTypeDescriptor javaTypeDescriptor) { + return new BasicBinder( javaTypeDescriptor, this ) { + @Override + protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) + throws SQLException { + WkbEncoder encoder = Wkb.newEncoder( Wkb.Dialect.MYSQL_WKB ); + Geometry geometry = getJavaDescriptor().unwrap( value, Geometry.class, options ); + ByteBuffer buffer = encoder.encode( geometry, ByteOrder.NDR ); + byte[] bytes = ( buffer == null ? null : buffer.toByteArray() ); + st.setBytes( index, bytes ); + } + }; } @Override - public ValueExtractor getExtractor(JavaTypeDescriptor javaTypeDescriptor) { - return (ValueExtractor) new MySQLGeometryValueExtractor(javaTypeDescriptor); + public ValueExtractor getExtractor(final JavaTypeDescriptor javaTypeDescriptor) { + return new BasicExtractor( javaTypeDescriptor, this ) { + + @Override + protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException { + return getJavaDescriptor().wrap( toGeometry( rs.getBytes( name ) ), options ); + } + + @Override + protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException { + return getJavaDescriptor().wrap( toGeometry( statement.getBytes( index ) ), options ); + } + + @Override + protected X doExtract(CallableStatement statement, String name, WrapperOptions options) + throws SQLException { + return getJavaDescriptor().wrap( toGeometry( statement.getBytes( name ) ), options ); + } + }; } + + private Geometry toGeometry(byte[] bytes) { + if ( bytes == null ) { + return null; + } + ByteBuffer buffer = ByteBuffer.from( bytes ); + WkbDecoder decoder = Wkb.newDecoder( Wkb.Dialect.MYSQL_WKB ); + return decoder.decode( buffer ); + } + } diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/mysql/MySQLGeometryValueBinder.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/mysql/MySQLGeometryValueBinder.java deleted file mode 100644 index 01ed469cad..0000000000 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/mysql/MySQLGeometryValueBinder.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * This file is part of Hibernate Spatial, an extension to the - * hibernate ORM solution for spatial (geographic) data. - * - * Copyright © 2007-2012 Geovise BVBA - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -package org.hibernate.spatial.dialect.mysql; - -import java.sql.Connection; - -import com.vividsolutions.jts.geom.Geometry; -import com.vividsolutions.jts.geom.GeometryCollection; -import com.vividsolutions.jts.geom.GeometryFactory; -import com.vividsolutions.jts.io.ByteOrderValues; -import com.vividsolutions.jts.io.WKBWriter; - -import org.hibernate.spatial.dialect.AbstractGeometryValueBinder; -import org.hibernate.spatial.jts.JTS; -import org.hibernate.type.descriptor.java.JavaTypeDescriptor; - -/** - * @author Karel Maesen, Geovise BVBA - * creation-date: 1/19/12 - */ -public class MySQLGeometryValueBinder extends AbstractGeometryValueBinder { - - private static final int SRIDLEN = 4; - - public MySQLGeometryValueBinder(JavaTypeDescriptor javaDescriptor) { - super( javaDescriptor, MySQLGeometryTypeDescriptor.INSTANCE ); - } - - @Override - protected Object toNative(Geometry jtsGeom, Connection connection) { - if ( jtsGeom.isEmpty() ) { - return null; - } - jtsGeom = forceGeometryCollection( jtsGeom ); - int srid = jtsGeom.getSRID(); - - WKBWriter writer = new WKBWriter( - 2, - ByteOrderValues.LITTLE_ENDIAN - ); - byte[] wkb = writer.write( jtsGeom ); - - byte[] byteArr = new byte[wkb.length + SRIDLEN]; - byteArr[3] = (byte) ( ( srid >> 24 ) & 0xFF ); - byteArr[2] = (byte) ( ( srid >> 16 ) & 0xFF ); - byteArr[1] = (byte) ( ( srid >> 8 ) & 0xFF ); - byteArr[0] = (byte) ( srid & 0xFF ); - System.arraycopy( wkb, 0, byteArr, SRIDLEN, wkb.length ); - return byteArr; - } - - private Geometry forceGeometryCollection(Geometry jtsGeom) { - if ( jtsGeom.isEmpty() ) { - return createEmptyGeometryCollection( jtsGeom ); - } - if ( jtsGeom instanceof GeometryCollection ) { - GeometryCollection gc = (GeometryCollection) jtsGeom; - Geometry[] components = new Geometry[gc.getNumGeometries()]; - for ( int i = 0; i < gc.getNumGeometries(); i++ ) { - Geometry component = gc.getGeometryN( i ); - if ( component.isEmpty() ) { - components[i] = jtsGeom.getFactory().createGeometryCollection( null ); - } - else { - components[i] = component; - } - } - Geometry geometryCollection = jtsGeom.getFactory().createGeometryCollection( components ); - geometryCollection.setSRID( jtsGeom.getSRID() ); - return geometryCollection; - } - return jtsGeom; - } - - private Geometry createEmptyGeometryCollection(Geometry jtsGeom) { - GeometryFactory factory = jtsGeom.getFactory(); - if ( factory == null ) { - factory = JTS.getDefaultGeometryFactory(); - } - Geometry empty = factory.createGeometryCollection( null ); - empty.setSRID( jtsGeom.getSRID() ); - return empty; - } -} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/mysql/MySQLGeometryValueExtractor.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/mysql/MySQLGeometryValueExtractor.java deleted file mode 100644 index d27a6fd79f..0000000000 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/mysql/MySQLGeometryValueExtractor.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * This file is part of Hibernate Spatial, an extension to the - * hibernate ORM solution for spatial (geographic) data. - * - * Copyright © 2007-2012 Geovise BVBA - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -package org.hibernate.spatial.dialect.mysql; - -import com.vividsolutions.jts.geom.Geometry; -import com.vividsolutions.jts.io.WKBReader; - -import org.hibernate.spatial.dialect.AbstractGeometryValueExtractor; -import org.hibernate.type.descriptor.java.JavaTypeDescriptor; - -/** - * @author Karel Maesen, Geovise BVBA - * creation-date: 1/19/12 - */ -public class MySQLGeometryValueExtractor extends AbstractGeometryValueExtractor { - - private static final int SRIDLEN = 4; - - public MySQLGeometryValueExtractor(JavaTypeDescriptor javaDescriptor) { - super( javaDescriptor, MySQLGeometryTypeDescriptor.INSTANCE ); - } - - /** - * Converts the native geometry object to a JTS Geometry. - * - * @param object native database geometry object (depends on the JDBC spatial - * extension of the database) - * - * @return JTS geometry corresponding to geomObj. - */ - public Geometry toJTS(Object object) { - if ( object == null ) { - return null; - } - byte[] data = (byte[]) object; - byte[] wkb = new byte[data.length - SRIDLEN]; - System.arraycopy( data, SRIDLEN, wkb, 0, wkb.length ); - int srid = 0; - // WKB in MySQL Spatial is always little endian. - srid = data[3] << 24 | ( data[2] & 0xff ) << 16 | ( data[1] & 0xff ) << 8 - | ( data[0] & 0xff ); - Geometry geom = null; - try { - WKBReader reader = new WKBReader(); - geom = reader.read( wkb ); - } - catch ( Exception e ) { - throw new RuntimeException( - "Couldn't parse incoming MySQL Spatial data." - ); - } - geom.setSRID( srid ); - return geom; - } - -} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PGGeometryTypeDescriptor.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PGGeometryTypeDescriptor.java index d99465449a..f6e242bd71 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PGGeometryTypeDescriptor.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PGGeometryTypeDescriptor.java @@ -21,12 +21,27 @@ package org.hibernate.spatial.dialect.postgis; +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; import java.sql.Types; +import org.geolatte.geom.ByteBuffer; +import org.geolatte.geom.ByteOrder; +import org.geolatte.geom.Geometry; +import org.geolatte.geom.codec.Wkb; +import org.geolatte.geom.codec.WkbDecoder; +import org.geolatte.geom.codec.WkbEncoder; +import org.postgresql.util.PGobject; + import org.hibernate.spatial.GeometrySqlTypeDescriptor; import org.hibernate.type.descriptor.ValueBinder; import org.hibernate.type.descriptor.ValueExtractor; +import org.hibernate.type.descriptor.WrapperOptions; import org.hibernate.type.descriptor.java.JavaTypeDescriptor; +import org.hibernate.type.descriptor.sql.BasicBinder; +import org.hibernate.type.descriptor.sql.BasicExtractor; /** * @author Karel Maesen, Geovise BVBA @@ -54,11 +69,52 @@ public class PGGeometryTypeDescriptor extends GeometrySqlTypeDescriptor { @Override public ValueBinder getBinder(final JavaTypeDescriptor javaTypeDescriptor) { - return (ValueBinder) new PGGeometryValueBinder(javaTypeDescriptor); + return new BasicBinder( javaTypeDescriptor, this ) { + @Override + protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) + throws SQLException { + WkbEncoder encoder = Wkb.newEncoder( Wkb.Dialect.POSTGIS_EWKB_1 ); + Geometry geometry = getJavaDescriptor().unwrap( value, Geometry.class, options ); + byte[] bytes = encoder.encode( geometry, ByteOrder.NDR ).toByteArray(); + st.setBytes( index, bytes ); + } + + }; } @Override public ValueExtractor getExtractor(final JavaTypeDescriptor javaTypeDescriptor) { - return (ValueExtractor) new PGGeometryValueExtractor(javaTypeDescriptor); + return new BasicExtractor( javaTypeDescriptor, this ) { + + @Override + protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException { + return getJavaDescriptor().wrap( toGeometry( rs.getObject( name ) ), options ); + } + + @Override + protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException { + return getJavaDescriptor().wrap( toGeometry( statement.getObject( index ) ), options ); + } + + @Override + protected X doExtract(CallableStatement statement, String name, WrapperOptions options) + throws SQLException { + return getJavaDescriptor().wrap( toGeometry( statement.getObject( name ) ), options ); + } + }; + } + + private Geometry toGeometry(Object object) { + if ( object == null ) { + return null; + } + ByteBuffer buffer = null; + if ( object instanceof PGobject ) { + buffer = ByteBuffer.from( ( (PGobject) object ).getValue() ); + WkbDecoder decoder = Wkb.newDecoder( Wkb.Dialect.POSTGIS_EWKB_1 ); + return decoder.decode( buffer ); + } + throw new IllegalStateException( "Received object of type " + object.getClass().getCanonicalName() ); + } } diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PGGeometryValueBinder.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PGGeometryValueBinder.java deleted file mode 100644 index aa868d611e..0000000000 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PGGeometryValueBinder.java +++ /dev/null @@ -1,293 +0,0 @@ -/* - * This file is part of Hibernate Spatial, an extension to the - * hibernate ORM solution for spatial (geographic) data. - * - * Copyright © 2007-2012 Geovise BVBA - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -package org.hibernate.spatial.dialect.postgis; - -import java.sql.Connection; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.Geometry; -import com.vividsolutions.jts.geom.GeometryFactory; -import org.postgis.GeometryCollection; -import org.postgis.LineString; -import org.postgis.LinearRing; -import org.postgis.MultiLineString; -import org.postgis.MultiPoint; -import org.postgis.MultiPolygon; -import org.postgis.PGgeometry; -import org.postgis.Point; -import org.postgis.Polygon; - -import org.hibernate.spatial.dialect.AbstractGeometryValueBinder; -import org.hibernate.spatial.jts.JTS; -import org.hibernate.spatial.jts.mgeom.MCoordinate; -import org.hibernate.spatial.jts.mgeom.MGeometry; -import org.hibernate.type.descriptor.java.JavaTypeDescriptor; - -/** - * @author Karel Maesen, Geovise BVBA - * creation-date: 7/27/11 - */ -public class PGGeometryValueBinder extends AbstractGeometryValueBinder { - - - public PGGeometryValueBinder(JavaTypeDescriptor javaDescriptor) { - super( javaDescriptor, PGGeometryTypeDescriptor.INSTANCE ); - } - - /** - * Converts a JTS Geometry to a native geometry object. - * - * @param jtsGeom JTS Geometry to convert - * @param connection the current database connection - * - * @return native database geometry object corresponding to jtsGeom. - */ - protected Object toNative(Geometry jtsGeom, Connection connection) { - org.postgis.Geometry geom = null; - jtsGeom = forceEmptyToGeometryCollection( jtsGeom ); - if ( jtsGeom instanceof com.vividsolutions.jts.geom.Point ) { - geom = convertJTSPoint( (com.vividsolutions.jts.geom.Point) jtsGeom ); - } - else if ( jtsGeom instanceof com.vividsolutions.jts.geom.LineString ) { - geom = convertJTSLineString( (com.vividsolutions.jts.geom.LineString) jtsGeom ); - } - else if ( jtsGeom instanceof com.vividsolutions.jts.geom.MultiLineString ) { - geom = convertJTSMultiLineString( (com.vividsolutions.jts.geom.MultiLineString) jtsGeom ); - } - else if ( jtsGeom instanceof com.vividsolutions.jts.geom.Polygon ) { - geom = convertJTSPolygon( (com.vividsolutions.jts.geom.Polygon) jtsGeom ); - } - else if ( jtsGeom instanceof com.vividsolutions.jts.geom.MultiPoint ) { - geom = convertJTSMultiPoint( (com.vividsolutions.jts.geom.MultiPoint) jtsGeom ); - } - else if ( jtsGeom instanceof com.vividsolutions.jts.geom.MultiPolygon ) { - geom = convertJTSMultiPolygon( (com.vividsolutions.jts.geom.MultiPolygon) jtsGeom ); - } - else if ( jtsGeom instanceof com.vividsolutions.jts.geom.GeometryCollection ) { - geom = convertJTSGeometryCollection( (com.vividsolutions.jts.geom.GeometryCollection) jtsGeom ); - } - - if ( geom != null ) { - return new PGgeometry( geom ); - } - else { - throw new UnsupportedOperationException( - "Conversion of " - + jtsGeom.getClass().getSimpleName() - + " to PGgeometry not supported" - ); - } - } - - //Postgis treats every empty geometry as an empty geometrycollection - - private Geometry forceEmptyToGeometryCollection(Geometry jtsGeom) { - Geometry forced = jtsGeom; - if ( forced.isEmpty() ) { - GeometryFactory factory = jtsGeom.getFactory(); - if ( factory == null ) { - factory = JTS.getDefaultGeometryFactory(); - } - forced = factory.createGeometryCollection( null ); - forced.setSRID( jtsGeom.getSRID() ); - } - return forced; - } - - private MultiPolygon convertJTSMultiPolygon( - com.vividsolutions.jts.geom.MultiPolygon multiPolygon) { - Polygon[] pgPolygons = new Polygon[multiPolygon.getNumGeometries()]; - for ( int i = 0; i < pgPolygons.length; i++ ) { - pgPolygons[i] = convertJTSPolygon( - (com.vividsolutions.jts.geom.Polygon) multiPolygon - .getGeometryN( i ) - ); - } - MultiPolygon mpg = new MultiPolygon( pgPolygons ); - mpg.setSrid( multiPolygon.getSRID() ); - return mpg; - } - - private MultiPoint convertJTSMultiPoint( - com.vividsolutions.jts.geom.MultiPoint multiPoint) { - Point[] pgPoints = new Point[multiPoint.getNumGeometries()]; - for ( int i = 0; i < pgPoints.length; i++ ) { - pgPoints[i] = convertJTSPoint( - (com.vividsolutions.jts.geom.Point) multiPoint - .getGeometryN( i ) - ); - } - MultiPoint mp = new MultiPoint( pgPoints ); - mp.setSrid( multiPoint.getSRID() ); - return mp; - } - - private Polygon convertJTSPolygon( - com.vividsolutions.jts.geom.Polygon jtsPolygon) { - int numRings = jtsPolygon.getNumInteriorRing(); - org.postgis.LinearRing[] rings = new org.postgis.LinearRing[numRings + 1]; - rings[0] = convertJTSLineStringToLinearRing( - jtsPolygon - .getExteriorRing() - ); - for ( int i = 0; i < numRings; i++ ) { - rings[i + 1] = convertJTSLineStringToLinearRing( - jtsPolygon - .getInteriorRingN( i ) - ); - } - Polygon polygon = new org.postgis.Polygon( rings ); - polygon.setSrid( jtsPolygon.getSRID() ); - return polygon; - } - - private LinearRing convertJTSLineStringToLinearRing( - com.vividsolutions.jts.geom.LineString lineString) { - LinearRing lr = new org.postgis.LinearRing( - toPoints( - lineString - .getCoordinates() - ) - ); - lr.setSrid( lineString.getSRID() ); - return lr; - } - - private LineString convertJTSLineString( - com.vividsolutions.jts.geom.LineString string) { - LineString ls = new org.postgis.LineString( - toPoints( - string - .getCoordinates() - ) - ); - if ( string instanceof MGeometry ) { - ls.haveMeasure = true; - } - ls.setSrid( string.getSRID() ); - return ls; - } - - private MultiLineString convertJTSMultiLineString( - com.vividsolutions.jts.geom.MultiLineString string) { - org.postgis.LineString[] lines = new org.postgis.LineString[string - .getNumGeometries()]; - for ( int i = 0; i < string.getNumGeometries(); i++ ) { - lines[i] = new org.postgis.LineString( - toPoints( - string.getGeometryN( - i - ).getCoordinates() - ) - ); - } - MultiLineString mls = new MultiLineString( lines ); - if ( string instanceof MGeometry ) { - mls.haveMeasure = true; - } - mls.setSrid( string.getSRID() ); - return mls; - } - - private Point convertJTSPoint(com.vividsolutions.jts.geom.Point point) { - org.postgis.Point pgPoint = new org.postgis.Point(); - pgPoint.srid = point.getSRID(); - pgPoint.x = point.getX(); - pgPoint.y = point.getY(); - Coordinate coordinate = point.getCoordinate(); - if ( Double.isNaN( coordinate.z ) ) { - pgPoint.dimension = 2; - } - else { - pgPoint.z = coordinate.z; - pgPoint.dimension = 3; - } - pgPoint.haveMeasure = false; - if ( coordinate instanceof MCoordinate && !Double.isNaN( ( (MCoordinate) coordinate ).m ) ) { - pgPoint.m = ( (MCoordinate) coordinate ).m; - pgPoint.haveMeasure = true; - } - return pgPoint; - } - - private GeometryCollection convertJTSGeometryCollection( - com.vividsolutions.jts.geom.GeometryCollection collection) { - com.vividsolutions.jts.geom.Geometry currentGeom; - org.postgis.Geometry[] pgCollections = new org.postgis.Geometry[collection - .getNumGeometries()]; - for ( int i = 0; i < pgCollections.length; i++ ) { - currentGeom = collection.getGeometryN( i ); - currentGeom = forceEmptyToGeometryCollection( currentGeom ); - if ( currentGeom.getClass() == com.vividsolutions.jts.geom.LineString.class ) { - pgCollections[i] = convertJTSLineString( (com.vividsolutions.jts.geom.LineString) currentGeom ); - } - else if ( currentGeom.getClass() == com.vividsolutions.jts.geom.LinearRing.class ) { - pgCollections[i] = convertJTSLineStringToLinearRing( (com.vividsolutions.jts.geom.LinearRing) currentGeom ); - } - else if ( currentGeom.getClass() == com.vividsolutions.jts.geom.MultiLineString.class ) { - pgCollections[i] = convertJTSMultiLineString( (com.vividsolutions.jts.geom.MultiLineString) currentGeom ); - } - else if ( currentGeom.getClass() == com.vividsolutions.jts.geom.MultiPoint.class ) { - pgCollections[i] = convertJTSMultiPoint( (com.vividsolutions.jts.geom.MultiPoint) currentGeom ); - } - else if ( currentGeom.getClass() == com.vividsolutions.jts.geom.MultiPolygon.class ) { - pgCollections[i] = convertJTSMultiPolygon( (com.vividsolutions.jts.geom.MultiPolygon) currentGeom ); - } - else if ( currentGeom.getClass() == com.vividsolutions.jts.geom.Point.class ) { - pgCollections[i] = convertJTSPoint( (com.vividsolutions.jts.geom.Point) currentGeom ); - } - else if ( currentGeom.getClass() == com.vividsolutions.jts.geom.Polygon.class ) { - pgCollections[i] = convertJTSPolygon( (com.vividsolutions.jts.geom.Polygon) currentGeom ); - } - else if ( currentGeom.getClass() == com.vividsolutions.jts.geom.GeometryCollection.class ) { - pgCollections[i] = convertJTSGeometryCollection( (com.vividsolutions.jts.geom.GeometryCollection) currentGeom ); - } - } - GeometryCollection gc = new GeometryCollection( pgCollections ); - gc.setSrid( collection.getSRID() ); - return gc; - } - - - private Point[] toPoints(Coordinate[] coordinates) { - Point[] points = new Point[coordinates.length]; - for ( int i = 0; i < coordinates.length; i++ ) { - Coordinate c = coordinates[i]; - Point pt; - if ( Double.isNaN( c.z ) ) { - pt = new Point( c.x, c.y ); - } - else { - pt = new Point( c.x, c.y, c.z ); - } - if ( c instanceof MCoordinate ) { - MCoordinate mc = (MCoordinate) c; - if ( !Double.isNaN( mc.m ) ) { - pt.setM( mc.m ); - } - } - points[i] = pt; - } - return points; - } - -} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PGGeometryValueExtractor.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PGGeometryValueExtractor.java deleted file mode 100644 index 9a917fcea1..0000000000 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PGGeometryValueExtractor.java +++ /dev/null @@ -1,284 +0,0 @@ -/* - * This file is part of Hibernate Spatial, an extension to the - * hibernate ORM solution for spatial (geographic) data. - * - * Copyright © 2007-2012 Geovise BVBA - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -package org.hibernate.spatial.dialect.postgis; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.Geometry; -import org.postgis.GeometryCollection; -import org.postgis.MultiLineString; -import org.postgis.MultiPoint; -import org.postgis.MultiPolygon; -import org.postgis.PGboxbase; -import org.postgis.PGgeometry; -import org.postgis.Point; -import org.postgis.Polygon; - -import org.hibernate.spatial.dialect.AbstractGeometryValueExtractor; -import org.hibernate.spatial.jts.mgeom.MCoordinate; -import org.hibernate.spatial.jts.mgeom.MLineString; -import org.hibernate.type.descriptor.java.JavaTypeDescriptor; - -/** - * @author Karel Maesen, Geovise BVBA - * creation-date: 7/27/11 - */ -public class PGGeometryValueExtractor extends AbstractGeometryValueExtractor { - - public PGGeometryValueExtractor(JavaTypeDescriptor javaDescriptor) { - super( javaDescriptor , PGGeometryTypeDescriptor.INSTANCE); - } - - public Geometry toJTS(Object object) { - if ( object == null ) { - return null; - } - - // in some cases, Postgis returns not PGgeometry objects - // but org.postgis.Geometry instances. - // This has been observed when retrieving GeometryCollections - // as the result of an SQL-operation such as Union. - if ( object instanceof org.postgis.Geometry ) { - object = new PGgeometry( (org.postgis.Geometry) object ); - } - - if ( object instanceof PGgeometry ) { - PGgeometry geom = (PGgeometry) object; - com.vividsolutions.jts.geom.Geometry out = null; - switch ( geom.getGeoType() ) { - case org.postgis.Geometry.POINT: - out = convertPoint( (org.postgis.Point) geom.getGeometry() ); - break; - case org.postgis.Geometry.LINESTRING: - out = convertLineString( - (org.postgis.LineString) geom - .getGeometry() - ); - break; - case org.postgis.Geometry.POLYGON: - out = convertPolygon( (org.postgis.Polygon) geom.getGeometry() ); - break; - case org.postgis.Geometry.MULTILINESTRING: - out = convertMultiLineString( - (org.postgis.MultiLineString) geom - .getGeometry() - ); - break; - case org.postgis.Geometry.MULTIPOINT: - out = convertMultiPoint( - (org.postgis.MultiPoint) geom - .getGeometry() - ); - break; - case org.postgis.Geometry.MULTIPOLYGON: - out = convertMultiPolygon( - (org.postgis.MultiPolygon) geom - .getGeometry() - ); - break; - case org.postgis.Geometry.GEOMETRYCOLLECTION: - out = convertGeometryCollection( - (org.postgis.GeometryCollection) geom - .getGeometry() - ); - break; - default: - throw new RuntimeException( "Unknown type of PGgeometry" ); - } - out.setSRID( geom.getGeometry().srid ); - return out; - } - else if ( object instanceof org.postgis.PGboxbase ) { - return convertBox( (org.postgis.PGboxbase) object ); - } - else { - throw new IllegalArgumentException( - "Can't convert object of type " - + object.getClass().getCanonicalName() - ); - - } - - } - - private Geometry convertBox(PGboxbase box) { - Point ll = box.getLLB(); - Point ur = box.getURT(); - Coordinate[] ringCoords = new Coordinate[5]; - if ( box instanceof org.postgis.PGbox2d ) { - ringCoords[0] = new Coordinate( ll.x, ll.y ); - ringCoords[1] = new Coordinate( ur.x, ll.y ); - ringCoords[2] = new Coordinate( ur.x, ur.y ); - ringCoords[3] = new Coordinate( ll.x, ur.y ); - ringCoords[4] = new Coordinate( ll.x, ll.y ); - } - else { - ringCoords[0] = new Coordinate( ll.x, ll.y, ll.z ); - ringCoords[1] = new Coordinate( ur.x, ll.y, ll.z ); - ringCoords[2] = new Coordinate( ur.x, ur.y, ur.z ); - ringCoords[3] = new Coordinate( ll.x, ur.y, ur.z ); - ringCoords[4] = new Coordinate( ll.x, ll.y, ll.z ); - } - com.vividsolutions.jts.geom.LinearRing shell = getGeometryFactory() - .createLinearRing( ringCoords ); - return getGeometryFactory().createPolygon( shell, null ); - } - - private Geometry convertGeometryCollection(GeometryCollection collection) { - org.postgis.Geometry[] geometries = collection.getGeometries(); - com.vividsolutions.jts.geom.Geometry[] jtsGeometries = new com.vividsolutions.jts.geom.Geometry[geometries.length]; - for ( int i = 0; i < geometries.length; i++ ) { - jtsGeometries[i] = toJTS( geometries[i] ); - //TODO - refactor this so the following line is not necessary - jtsGeometries[i].setSRID( 0 ); // convert2JTS sets SRIDs, but constituent geometries in a collection must have srid == 0 - } - com.vividsolutions.jts.geom.GeometryCollection jtsGCollection = getGeometryFactory() - .createGeometryCollection( jtsGeometries ); - return jtsGCollection; - } - - private Geometry convertMultiPolygon(MultiPolygon pgMultiPolygon) { - com.vividsolutions.jts.geom.Polygon[] polygons = new com.vividsolutions.jts.geom.Polygon[pgMultiPolygon - .numPolygons()]; - - for ( int i = 0; i < polygons.length; i++ ) { - Polygon pgPolygon = pgMultiPolygon.getPolygon( i ); - polygons[i] = (com.vividsolutions.jts.geom.Polygon) convertPolygon( pgPolygon ); - } - - com.vividsolutions.jts.geom.MultiPolygon out = getGeometryFactory() - .createMultiPolygon( polygons ); - return out; - } - - private Geometry convertMultiPoint(MultiPoint pgMultiPoint) { - com.vividsolutions.jts.geom.Point[] points = new com.vividsolutions.jts.geom.Point[pgMultiPoint - .numPoints()]; - - for ( int i = 0; i < points.length; i++ ) { - points[i] = convertPoint( pgMultiPoint.getPoint( i ) ); - } - com.vividsolutions.jts.geom.MultiPoint out = getGeometryFactory() - .createMultiPoint( points ); - out.setSRID( pgMultiPoint.srid ); - return out; - } - - private com.vividsolutions.jts.geom.Geometry convertMultiLineString( - MultiLineString mlstr) { - com.vividsolutions.jts.geom.MultiLineString out; - if ( mlstr.haveMeasure ) { - MLineString[] lstrs = new MLineString[mlstr.numLines()]; - for ( int i = 0; i < mlstr.numLines(); i++ ) { - MCoordinate[] coordinates = toJTSCoordinates( - mlstr.getLine( i ) - .getPoints() - ); - lstrs[i] = getGeometryFactory().createMLineString( coordinates ); - } - out = getGeometryFactory().createMultiMLineString( lstrs ); - } - else { - com.vividsolutions.jts.geom.LineString[] lstrs = new com.vividsolutions.jts.geom.LineString[mlstr - .numLines()]; - for ( int i = 0; i < mlstr.numLines(); i++ ) { - lstrs[i] = getGeometryFactory().createLineString( - toJTSCoordinates( mlstr.getLine( i ).getPoints() ) - ); - } - out = getGeometryFactory().createMultiLineString( lstrs ); - } - return out; - } - - private com.vividsolutions.jts.geom.Geometry convertPolygon( - Polygon polygon) { - com.vividsolutions.jts.geom.LinearRing shell = getGeometryFactory() - .createLinearRing( - toJTSCoordinates( polygon.getRing( 0 ).getPoints() ) - ); - com.vividsolutions.jts.geom.Polygon out = null; - if ( polygon.numRings() > 1 ) { - com.vividsolutions.jts.geom.LinearRing[] rings = new com.vividsolutions.jts.geom.LinearRing[polygon - .numRings() - 1]; - for ( int r = 1; r < polygon.numRings(); r++ ) { - rings[r - 1] = getGeometryFactory().createLinearRing( - toJTSCoordinates( polygon.getRing( r ).getPoints() ) - ); - } - out = getGeometryFactory().createPolygon( shell, rings ); - } - else { - out = getGeometryFactory().createPolygon( shell, null ); - } - return out; - } - - private com.vividsolutions.jts.geom.Point convertPoint(Point pnt) { - com.vividsolutions.jts.geom.Point g = getGeometryFactory().createPoint( - this.toJTSCoordinate( pnt ) - ); - return g; - } - - private com.vividsolutions.jts.geom.LineString convertLineString( - org.postgis.LineString lstr) { - com.vividsolutions.jts.geom.LineString out = lstr.haveMeasure ? getGeometryFactory() - .createMLineString( toJTSCoordinates( lstr.getPoints() ) ) - : getGeometryFactory().createLineString( - toJTSCoordinates( lstr.getPoints() ) - ); - return out; - } - - private MCoordinate[] toJTSCoordinates(Point[] points) { - MCoordinate[] coordinates = new MCoordinate[points.length]; - for ( int i = 0; i < points.length; i++ ) { - coordinates[i] = this.toJTSCoordinate( points[i] ); - } - return coordinates; - } - - private MCoordinate toJTSCoordinate(Point pt) { - MCoordinate mc; - if ( pt.dimension == 2 ) { - mc = pt.haveMeasure ? MCoordinate.create2dWithMeasure( - pt.getX(), pt - .getY(), pt.getM() - ) : MCoordinate.create2d( - pt.getX(), pt - .getY() - ); - } - else { - mc = pt.haveMeasure ? MCoordinate.create3dWithMeasure( - pt.getX(), pt - .getY(), pt.getZ(), pt.getM() - ) : MCoordinate.create3d( - pt - .getX(), pt.getY(), pt.getZ() - ); - } - return mc; - } - - -} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/AbstractEncoder.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/AbstractEncoder.java index 72ebaab5bc..bef1446b88 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/AbstractEncoder.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/AbstractEncoder.java @@ -40,7 +40,7 @@ abstract class AbstractEncoder implements Encoder { nativeGeom.setHasMValues(); } - CountingPointSequenceBuilder coordinates = new CountingPointSequenceBuilder(geom.getDimensionalFlag()); + CountingPointSequenceBuilder coordinates = new CountingPointSequenceBuilder(geom.getDimensionalFlag(), geom.getCrsId()); List
figures = new ArrayList
(); List shapes = new ArrayList(); diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/CountingPointSequenceBuilder.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/CountingPointSequenceBuilder.java index 76d5a4b9a2..2ff166e410 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/CountingPointSequenceBuilder.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/CountingPointSequenceBuilder.java @@ -1,6 +1,7 @@ package org.hibernate.spatial.dialect.sqlserver.convertors; import org.geolatte.geom.*; +import org.geolatte.geom.crs.CrsId; /** * @author Karel Maesen, Geovise BVBA @@ -11,8 +12,8 @@ public class CountingPointSequenceBuilder implements PointSequenceBuilder { final private PointSequenceBuilder delegate; private int num = 0; - public CountingPointSequenceBuilder(DimensionalFlag df) { - delegate = PointSequenceBuilders.variableSized(df); + public CountingPointSequenceBuilder(DimensionalFlag df, CrsId crsId) { + delegate = PointSequenceBuilders.variableSized(df, crsId); } @Override @@ -50,7 +51,12 @@ public class CountingPointSequenceBuilder implements PointSequenceBuilder { return delegate.getDimensionalFlag(); } - @Override + @Override + public CrsId getCrsId() { + return delegate.getCrsId(); + } + + @Override public PointSequence toPointSequence() { return delegate.toPointSequence(); } diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/LineStringDecoder.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/LineStringDecoder.java index 2aa7d9a6e1..279808ab56 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/LineStringDecoder.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/LineStringDecoder.java @@ -23,7 +23,6 @@ package org.hibernate.spatial.dialect.sqlserver.convertors; import org.geolatte.geom.LineString; import org.geolatte.geom.PointSequence; -import org.geolatte.geom.crs.CrsId; class LineStringDecoder extends AbstractDecoder { @@ -53,6 +52,6 @@ class LineStringDecoder extends AbstractDecoder { protected LineString createLineString(SqlServerGeometry nativeGeom, IndexRange pntIndexRange) { PointSequence coordinates = nativeGeom.coordinateRange( pntIndexRange ); - return new LineString(coordinates, CrsId.valueOf(nativeGeom.getSrid())); + return new LineString(coordinates); } } diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/PointDecoder.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/PointDecoder.java index 87459ecf39..b7c7737cf8 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/PointDecoder.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/PointDecoder.java @@ -25,7 +25,6 @@ package org.hibernate.spatial.dialect.sqlserver.convertors; import org.geolatte.geom.DimensionalFlag; import org.geolatte.geom.Point; import org.geolatte.geom.PointSequence; -import org.geolatte.geom.crs.CrsId; /** * @author Karel Maesen, Geovise BVBA. @@ -60,7 +59,7 @@ class PointDecoder extends AbstractDecoder { private Point createPoint(SqlServerGeometry nativeGeom, int pntOffset) { DimensionalFlag df = DimensionalFlag.valueOf(nativeGeom.hasZValues(), nativeGeom.hasMValues()); PointSequence pointSequence = nativeGeom.coordinateRange(new IndexRange(pntOffset, pntOffset + 1)); - return new Point(pointSequence, CrsId.valueOf(nativeGeom.getSrid())); + return new Point(pointSequence); } diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/PolygonDecoder.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/PolygonDecoder.java index 94ce79f1ca..5eba78e321 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/PolygonDecoder.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/PolygonDecoder.java @@ -24,7 +24,6 @@ package org.hibernate.spatial.dialect.sqlserver.convertors; import org.geolatte.geom.LinearRing; import org.geolatte.geom.PointSequence; import org.geolatte.geom.Polygon; -import org.geolatte.geom.crs.CrsId; /** * @author Karel Maesen, Geovise BVBA @@ -67,7 +66,7 @@ class PolygonDecoder extends AbstractDecoder { private LinearRing toLinearRing(SqlServerGeometry nativeGeom, IndexRange range) { PointSequence pointSequence = nativeGeom.coordinateRange(range); - return new LinearRing(pointSequence, CrsId.valueOf(nativeGeom.getSrid())); + return new LinearRing(pointSequence); } } diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/SqlServerGeometry.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/SqlServerGeometry.java index 7197887c63..5af47195d7 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/SqlServerGeometry.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/SqlServerGeometry.java @@ -30,6 +30,7 @@ import org.geolatte.geom.PointCollection; import org.geolatte.geom.PointSequence; import org.geolatte.geom.PointSequenceBuilder; import org.geolatte.geom.PointSequenceBuilders; +import org.geolatte.geom.crs.CrsId; import org.hibernate.spatial.jts.mgeom.MCoordinate; @@ -123,17 +124,17 @@ public class SqlServerGeometry { } void copyCoordinate(int index, double[] coords, DimensionalFlag df) { - coords[0] = points[2 * index]; - coords[1] = points[2 * index + 1]; - if (hasZValues()) { - assert(df.is3D()); - coords[df.Z] = zValues[index]; - } - if (hasMValues()) { - assert (df.isMeasured()); - coords[df.M] = mValues[index]; - } - } + coords[0] = points[2 * index]; + coords[1] = points[2 * index + 1]; + if ( hasZValues() ) { + assert ( df.is3D() ); + coords[df.Z] = zValues[index]; + } + if ( hasMValues() ) { + assert ( df.isMeasured() ); + coords[df.M] = mValues[index]; + } + } boolean isParentShapeOf(int parent, int child) { return getShape( child ).parentOffset == parent; @@ -188,15 +189,19 @@ public class SqlServerGeometry { } PointSequence coordinateRange(IndexRange range) { - DimensionalFlag df = DimensionalFlag.valueOf(hasZValues(), hasMValues()); - PointSequenceBuilder psBuilder = PointSequenceBuilders.fixedSized(range.end - range.start, df); - double[] coordinates = new double[df.getCoordinateDimension()]; - for (int idx = range.start, i = 0; idx < range.end; idx++, i++) { - copyCoordinate(idx, coordinates, df); - psBuilder.add(coordinates); - } - return psBuilder.toPointSequence(); - } + DimensionalFlag df = DimensionalFlag.valueOf( hasZValues(), hasMValues() ); + PointSequenceBuilder psBuilder = PointSequenceBuilders.fixedSized( + range.end - range.start, + df, + CrsId.valueOf( getSrid() ) + ); + double[] coordinates = new double[df.getCoordinateDimension()]; + for ( int idx = range.start, i = 0; idx < range.end; idx++, i++ ) { + copyCoordinate( idx, coordinates, df ); + psBuilder.add( coordinates ); + } + return psBuilder.toPointSequence(); + } private Coordinate[] createCoordinateArray(int size) { if ( hasMValues() ) { @@ -217,13 +222,13 @@ public class SqlServerGeometry { } void setCoordinate(int index, PointCollection coordinate) { - points[2 * index] = coordinate.getX(index); - points[2 * index + 1] = coordinate.getY(index); + points[2 * index] = coordinate.getX( index ); + points[2 * index + 1] = coordinate.getY( index ); if ( hasZValues() ) { - zValues[index] = coordinate.getZ(index); + zValues[index] = coordinate.getZ( index ); } if ( hasMValues() ) { - mValues[index] = coordinate.getM(index); + mValues[index] = coordinate.getM( index ); } } diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/LineStringConvertorTest.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/LineStringConvertorTest.java index bc84e88d97..03552ffc45 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/LineStringConvertorTest.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/LineStringConvertorTest.java @@ -26,6 +26,7 @@ import org.geolatte.geom.DimensionalFlag; import org.geolatte.geom.LineString; import org.geolatte.geom.PointCollection; import org.geolatte.geom.PointSequenceBuilders; +import org.geolatte.geom.crs.CrsId; import org.junit.Test; import org.hibernate.spatial.dialect.sqlserver.SqlServer2008SpatialDialect; @@ -38,6 +39,8 @@ import static org.junit.Assert.assertTrue; @RequiresDialect(SqlServer2008SpatialDialect.class) public class LineStringConvertorTest extends AbstractConvertorTest { + CrsId WGS84 = CrsId.valueOf( 4326 ); + @BeforeClassOnce public void beforeClass() { super.beforeClass(); @@ -67,26 +70,26 @@ public class LineStringConvertorTest extends AbstractConvertorTest { public void test_coordinates() { PointCollection received = decodedGeoms.get( 5 ).getPoints(); - PointCollection expected = PointSequenceBuilders.fixedSized( 2, DimensionalFlag.XY ).add(10, 5).add(20,15).toPointSequence(); + PointCollection expected = PointSequenceBuilders.fixedSized( 2, DimensionalFlag.d2D, WGS84 ).add(10, 5).add(20,15).toPointSequence(); assertPointCollectionEquality( received, expected ); received = decodedGeoms.get( 6 ).getPoints(); - expected = PointSequenceBuilders.fixedSized( 4, DimensionalFlag.XY).add(10,5).add(20,15).add(30.3, 22.4).add(10,30).toPointSequence(); + expected = PointSequenceBuilders.fixedSized( 4, DimensionalFlag.d2D, WGS84).add(10,5).add(20,15).add(30.3, 22.4).add(10,30).toPointSequence(); assertPointCollectionEquality( received, expected ); received = decodedGeoms.get( 7 ).getPoints(); - expected = PointSequenceBuilders.fixedSized( 2, DimensionalFlag.XYZ).add(10,5,0).add(20,15,3).toPointSequence(); + expected = PointSequenceBuilders.fixedSized( 2, DimensionalFlag.d3D, WGS84).add(10,5,0).add(20,15,3).toPointSequence(); assertPointCollectionEquality( received, expected ); //case 9 received = decodedGeoms.get( 9 ).getPoints(); - expected = PointSequenceBuilders.fixedSized( 4, DimensionalFlag.XYZ).add(10,5,1).add(20,15,2).add(30.3, 22.4,5).add(10,30,2).toPointSequence(); + expected = PointSequenceBuilders.fixedSized( 4, DimensionalFlag.d3D, WGS84).add(10,5,1).add(20,15,2).add(30.3, 22.4,5).add(10,30,2).toPointSequence(); assertPointCollectionEquality( received, expected ); //case 10 received = decodedGeoms.get( 10 ).getPoints(); - expected = PointSequenceBuilders.fixedSized( 4, DimensionalFlag.XYZM).add(10,5,1,1).add(20,15,2,3).add(30.3, 22.4,5,10).add(10,30,2,12).toPointSequence(); + expected = PointSequenceBuilders.fixedSized( 4, DimensionalFlag.d3DM, WGS84).add(10,5,1,1).add(20,15,2,3).add(30.3, 22.4,5,10).add(10,30,2,12).toPointSequence(); assertPointCollectionEquality( received, expected ); } diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/PointConvertorTest.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/PointConvertorTest.java index 9b22498a69..b94ca206bb 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/PointConvertorTest.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/PointConvertorTest.java @@ -63,13 +63,13 @@ public class PointConvertorTest extends AbstractConvertorTest { @Test public void test_coordinates() { Point expected; - expected = Points.create( 10.0, 5.0); + expected = Points.create2D( 10.0, 5.0); assertEquals( expected, decodedGeoms.get( 1 ).getPointN(0) ); - expected = Points.create(52.25, 2.53, CrsId.valueOf(4326)); + expected = Points.create2D(52.25, 2.53, CrsId.valueOf(4326)); assertEquals( expected, decodedGeoms.get( 2 ).getPointN( 0 ) ); - expected = Points.create(150000.0, 200000.0, CrsId.valueOf(31370)); + expected = Points.create2D(150000.0, 200000.0, CrsId.valueOf(31370)); assertEquals( expected, decodedGeoms.get( 3 ).getPointN( 0 ) ); - expected = Points.create(10.0, 2.0, 1.0, 3.0, CrsId.valueOf(4326)); + expected = Points.create3DM(10.0, 2.0, 1.0, 3.0, CrsId.valueOf(4326)); assertEquals( expected, decodedGeoms.get( 4 ).getPointN( 0 ) ); } diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/GeomEntity.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/GeomEntity.java index ea6ae3bf7a..e59d19a19a 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/GeomEntity.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/GeomEntity.java @@ -73,11 +73,10 @@ public class GeomEntity { } public static GeomEntity createFrom(TestDataElement element) throws ParseException { - WktDecoder decoder = Wkt.newWktDecoder( Wkt.Dialect.POSTGIS_EWKT_1 ); - Geometry geom = JTS.to( decoder.decode( element.wkt ) ); + WktDecoder decoder = Wkt.newDecoder( Wkt.Dialect.POSTGIS_EWKT_1 ); + Geometry geom = JTS.to( decoder.decode( element.wkt) ); GeomEntity result = new GeomEntity(); result.setId( element.id ); - geom.setSRID( element.srid ); result.setGeom( geom ); result.setType( element.type ); return result; diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/DataSourceUtils.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/DataSourceUtils.java index 1dba9a40a4..7d6b918552 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/DataSourceUtils.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/DataSourceUtils.java @@ -21,21 +21,31 @@ package org.hibernate.spatial.testing; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.StringWriter; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; +import javax.sql.DataSource; + import org.apache.commons.dbcp.BasicDataSource; import org.geolatte.geom.Geometry; import org.geolatte.geom.codec.Wkt; import org.geolatte.geom.codec.WktDecodeException; import org.geolatte.geom.codec.WktDecoder; + import org.hibernate.spatial.Log; import org.hibernate.spatial.LogFactory; -import javax.sql.DataSource; -import java.io.*; -import java.sql.*; -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; - /** *

Unit testsuite-suite support class.

* @@ -347,13 +357,11 @@ public class DataSourceUtils { */ public Map expectedGeoms(String type, TestData testData) { Map result = new HashMap(); - WktDecoder decoder = Wkt.newWktDecoder(); + WktDecoder decoder = Wkt.newDecoder(); for ( TestDataElement testDataElement : testData ) { if ( testDataElement.type.equalsIgnoreCase( type ) ) { try { - //to ensure expected geometries have the correct SRID, we prepend to the WKT string - String wkt = "SRID=" + testDataElement.srid + ";"+testDataElement.wkt; - result.put( testDataElement.id, decoder.decode( wkt ) ); + result.put( testDataElement.id, decoder.decode( testDataElement.wkt ) ); } catch ( WktDecodeException e ) { System.out diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/TestDataElement.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/TestDataElement.java index 5b62024557..b7ca9eeb7b 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/TestDataElement.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/TestDataElement.java @@ -31,14 +31,12 @@ public class TestDataElement { final public String wkt; final public int id; - final public int srid; final public String type; - protected TestDataElement(int id, String type, String wkt, int srid) { + protected TestDataElement(int id, String type, String wkt) { this.wkt = wkt; this.id = id; this.type = type; - this.srid = srid; } } diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/TestDataReader.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/TestDataReader.java index b3f3934384..af243e7263 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/TestDataReader.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/TestDataReader.java @@ -61,8 +61,7 @@ public class TestDataReader { int id = Integer.valueOf( element.selectSingleNode( "id" ).getText() ); String type = element.selectSingleNode( "type" ).getText(); String wkt = element.selectSingleNode( "wkt" ).getText(); - int srid = Integer.valueOf( element.selectSingleNode( "srid" ).getText() ); - TestDataElement testDataElement = new TestDataElement( id, type, wkt, srid ); + TestDataElement testDataElement = new TestDataElement( id, type, wkt); testDataElements.add( testDataElement ); } diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/WktUtility.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/WktUtility.java new file mode 100644 index 0000000000..d17950d5f7 --- /dev/null +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/WktUtility.java @@ -0,0 +1,30 @@ +package org.hibernate.spatial.testing; + +/** + * @author Karel Maesen, Geovise BVBA + * creation-date: 1/24/13 + */ +public class WktUtility { + + static public int getSRID(String wkt) { + String[] tokens = wkt.split( ";" ); + if (tokens.length == 1){ + return 0; + } + String[] sridTokens = tokens[0].split("="); + if ( sridTokens.length < 2 ) { + throw new IllegalArgumentException( "Can't parse " + wkt ); + } + return Integer.parseInt( sridTokens[1] ); + } + + static public String getWkt(String wkt) { + String[] tokens = wkt.split(";"); + if ( tokens.length > 1 ) { + return tokens[1]; + } else { + return wkt; + } + + } +} diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/h2geodb/GeoDBExpectationsFactory.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/h2geodb/GeoDBExpectationsFactory.java index f45885438b..f2500485be 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/h2geodb/GeoDBExpectationsFactory.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/h2geodb/GeoDBExpectationsFactory.java @@ -26,9 +26,9 @@ package org.hibernate.spatial.testing.dialects.h2geodb; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.Point; +import org.geolatte.geom.jts.JTS; -import org.hibernate.spatial.JTSGeometryJavaTypeDescriptor; -import org.hibernate.spatial.dialect.h2geodb.GeoDBValueExtractor; +import org.hibernate.spatial.dialect.h2geodb.GeoDbWkb; import org.hibernate.spatial.testing.AbstractExpectationsFactory; import org.hibernate.spatial.testing.NativeSQLStatement; @@ -41,43 +41,20 @@ import org.hibernate.spatial.testing.NativeSQLStatement; */ public class GeoDBExpectationsFactory extends AbstractExpectationsFactory { - private final GeoDBValueExtractor decoder = new GeoDBValueExtractor( JTSGeometryJavaTypeDescriptor.INSTANCE ); - public GeoDBExpectationsFactory(GeoDBDataSourceUtils dataSourceUtils) { super( dataSourceUtils ); } - /* - * (non-Javadoc) - * - * @seeorg.hibernatespatial.test.AbstractExpectationsFactory# - * createNativeAsBinaryStatement() - */ - @Override protected NativeSQLStatement createNativeAsBinaryStatement() { return createNativeSQLStatement( "select id, ST_AsEWKB(geom) from GEOMTEST" ); } - /* - * (non-Javadoc) - * - * @seeorg.hibernatespatial.test.AbstractExpectationsFactory# - * createNativeAsTextStatement() - */ - @Override protected NativeSQLStatement createNativeAsTextStatement() { return createNativeSQLStatement( "select id, ST_AsText(geom) from GEOMTEST" ); } - /* - * (non-Javadoc) - * - * @seeorg.hibernatespatial.test.AbstractExpectationsFactory# - * createNativeBoundaryStatement() - */ - @Override protected NativeSQLStatement createNativeBoundaryStatement() { throw new UnsupportedOperationException( @@ -85,13 +62,6 @@ public class GeoDBExpectationsFactory extends AbstractExpectationsFactory { ); } - /* - * (non-Javadoc) - * - * @seeorg.hibernatespatial.test.AbstractExpectationsFactory# - * createNativeBufferStatement(java.lang.Double) - */ - @Override protected NativeSQLStatement createNativeBufferStatement(Double distance) { return createNativeSQLStatement( @@ -100,13 +70,6 @@ public class GeoDBExpectationsFactory extends AbstractExpectationsFactory { ); } - /* - * (non-Javadoc) - * - * @seeorg.hibernatespatial.test.AbstractExpectationsFactory# - * createNativeContainsStatement(com.vividsolutions.jts.geom.Geometry) - */ - @Override protected NativeSQLStatement createNativeContainsStatement(Geometry geom) { return createNativeSQLStatementAllWKTParams( @@ -115,13 +78,6 @@ public class GeoDBExpectationsFactory extends AbstractExpectationsFactory { ); } - /* - * (non-Javadoc) - * - * @seeorg.hibernatespatial.test.AbstractExpectationsFactory# - * createNativeConvexHullStatement(com.vividsolutions.jts.geom.Geometry) - */ - @Override protected NativeSQLStatement createNativeConvexHullStatement(Geometry geom) { throw new UnsupportedOperationException( @@ -129,13 +85,6 @@ public class GeoDBExpectationsFactory extends AbstractExpectationsFactory { ); } - /* - * (non-Javadoc) - * - * @seeorg.hibernatespatial.test.AbstractExpectationsFactory# - * createNativeCrossesStatement(com.vividsolutions.jts.geom.Geometry) - */ - @Override protected NativeSQLStatement createNativeCrossesStatement(Geometry geom) { return createNativeSQLStatementAllWKTParams( @@ -144,13 +93,6 @@ public class GeoDBExpectationsFactory extends AbstractExpectationsFactory { ); } - /* - * (non-Javadoc) - * - * @seeorg.hibernatespatial.test.AbstractExpectationsFactory# - * createNativeDifferenceStatement(com.vividsolutions.jts.geom.Geometry) - */ - @Override protected NativeSQLStatement createNativeDifferenceStatement(Geometry geom) { throw new UnsupportedOperationException( @@ -158,13 +100,6 @@ public class GeoDBExpectationsFactory extends AbstractExpectationsFactory { ); } - /* - * (non-Javadoc) - * - * @seeorg.hibernatespatial.test.AbstractExpectationsFactory# - * createNativeDimensionSQL() - */ - @Override protected NativeSQLStatement createNativeDimensionSQL() { throw new UnsupportedOperationException( @@ -172,13 +107,6 @@ public class GeoDBExpectationsFactory extends AbstractExpectationsFactory { ); } - /* - * (non-Javadoc) - * - * @seeorg.hibernatespatial.test.AbstractExpectationsFactory# - * createNativeDisjointStatement(com.vividsolutions.jts.geom.Geometry) - */ - @Override protected NativeSQLStatement createNativeDisjointStatement(Geometry geom) { return createNativeSQLStatementAllWKTParams( @@ -439,17 +367,9 @@ public class GeoDBExpectationsFactory extends AbstractExpectationsFactory { ); } - /* - * (non-Javadoc) - * - * @see - * org.hibernatespatial.test.AbstractExpectationsFactory#decode(java.lang - * .Object) - */ - @Override protected Geometry decode(Object o) { - return decoder.toJTS( o ); + return JTS.to( GeoDbWkb.from( o ) ); } } diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/h2geodb/GeoDBExpressionTemplate.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/h2geodb/GeoDBExpressionTemplate.java index 285caa9648..694cac728f 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/h2geodb/GeoDBExpressionTemplate.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/h2geodb/GeoDBExpressionTemplate.java @@ -23,6 +23,7 @@ package org.hibernate.spatial.testing.dialects.h2geodb; import org.hibernate.spatial.testing.SQLExpressionTemplate; import org.hibernate.spatial.testing.TestDataElement; +import org.hibernate.spatial.testing.WktUtility; /** * This is the template for insert SQL statements into the geomtest test table @@ -41,10 +42,14 @@ public class GeoDBExpressionTemplate implements SQLExpressionTemplate { * hibernatespatial.test.TestDataElement) */ public String toInsertSql(TestDataElement testDataElement) { + String wkt = WktUtility.getWkt( testDataElement.wkt ); + int srid = WktUtility.getSRID( testDataElement.wkt ); return String - .format( - SQL_TEMPLATE, testDataElement.id, testDataElement.type, - testDataElement.wkt, testDataElement.srid + .format( SQL_TEMPLATE, + testDataElement.id, + testDataElement.type, + wkt, + srid ); } diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/h2geodb/GeoDBNoSRIDExpectationsFactory.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/h2geodb/GeoDBNoSRIDExpectationsFactory.java index 3bbb361ef8..e849a8d44f 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/h2geodb/GeoDBNoSRIDExpectationsFactory.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/h2geodb/GeoDBNoSRIDExpectationsFactory.java @@ -26,9 +26,10 @@ package org.hibernate.spatial.testing.dialects.h2geodb; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.Point; +import org.geolatte.geom.ByteBuffer; +import org.geolatte.geom.codec.Wkb; +import org.geolatte.geom.jts.JTS; -import org.hibernate.spatial.JTSGeometryJavaTypeDescriptor; -import org.hibernate.spatial.dialect.h2geodb.GeoDBValueExtractor; import org.hibernate.spatial.testing.AbstractExpectationsFactory; import org.hibernate.spatial.testing.NativeSQLStatement; @@ -41,43 +42,20 @@ import org.hibernate.spatial.testing.NativeSQLStatement; */ public class GeoDBNoSRIDExpectationsFactory extends AbstractExpectationsFactory { - private final GeoDBValueExtractor decoder = new GeoDBValueExtractor( JTSGeometryJavaTypeDescriptor.INSTANCE ); - public GeoDBNoSRIDExpectationsFactory(GeoDBDataSourceUtils dataSourceUtils) { super( dataSourceUtils ); } - /* - * (non-Javadoc) - * - * @seeorg.hibernatespatial.test.AbstractExpectationsFactory# - * createNativeAsBinaryStatement() - */ - @Override protected NativeSQLStatement createNativeAsBinaryStatement() { return createNativeSQLStatement( "select id, ST_AsEWKB(geom) from GEOMTEST" ); } - /* - * (non-Javadoc) - * - * @seeorg.hibernatespatial.test.AbstractExpectationsFactory# - * createNativeAsTextStatement() - */ - @Override protected NativeSQLStatement createNativeAsTextStatement() { return createNativeSQLStatement( "select id, ST_AsText(geom) from GEOMTEST" ); } - /* - * (non-Javadoc) - * - * @seeorg.hibernatespatial.test.AbstractExpectationsFactory# - * createNativeBoundaryStatement() - */ - @Override protected NativeSQLStatement createNativeBoundaryStatement() { throw new UnsupportedOperationException( @@ -85,13 +63,6 @@ public class GeoDBNoSRIDExpectationsFactory extends AbstractExpectationsFactory ); } - /* - * (non-Javadoc) - * - * @seeorg.hibernatespatial.test.AbstractExpectationsFactory# - * createNativeBufferStatement(java.lang.Double) - */ - @Override protected NativeSQLStatement createNativeBufferStatement(Double distance) { return createNativeSQLStatement( @@ -100,13 +71,6 @@ public class GeoDBNoSRIDExpectationsFactory extends AbstractExpectationsFactory ); } - /* - * (non-Javadoc) - * - * @seeorg.hibernatespatial.test.AbstractExpectationsFactory# - * createNativeContainsStatement(com.vividsolutions.jts.geom.Geometry) - */ - @Override protected NativeSQLStatement createNativeContainsStatement(Geometry geom) { return createNativeSQLStatementAllWKTParams( @@ -115,13 +79,6 @@ public class GeoDBNoSRIDExpectationsFactory extends AbstractExpectationsFactory ); } - /* - * (non-Javadoc) - * - * @seeorg.hibernatespatial.test.AbstractExpectationsFactory# - * createNativeConvexHullStatement(com.vividsolutions.jts.geom.Geometry) - */ - @Override protected NativeSQLStatement createNativeConvexHullStatement(Geometry geom) { throw new UnsupportedOperationException( @@ -129,13 +86,6 @@ public class GeoDBNoSRIDExpectationsFactory extends AbstractExpectationsFactory ); } - /* - * (non-Javadoc) - * - * @seeorg.hibernatespatial.test.AbstractExpectationsFactory# - * createNativeCrossesStatement(com.vividsolutions.jts.geom.Geometry) - */ - @Override protected NativeSQLStatement createNativeCrossesStatement(Geometry geom) { return createNativeSQLStatementAllWKTParams( @@ -144,13 +94,6 @@ public class GeoDBNoSRIDExpectationsFactory extends AbstractExpectationsFactory ); } - /* - * (non-Javadoc) - * - * @seeorg.hibernatespatial.test.AbstractExpectationsFactory# - * createNativeDifferenceStatement(com.vividsolutions.jts.geom.Geometry) - */ - @Override protected NativeSQLStatement createNativeDifferenceStatement(Geometry geom) { throw new UnsupportedOperationException( @@ -158,13 +101,6 @@ public class GeoDBNoSRIDExpectationsFactory extends AbstractExpectationsFactory ); } - /* - * (non-Javadoc) - * - * @seeorg.hibernatespatial.test.AbstractExpectationsFactory# - * createNativeDimensionSQL() - */ - @Override protected NativeSQLStatement createNativeDimensionSQL() { throw new UnsupportedOperationException( @@ -172,13 +108,6 @@ public class GeoDBNoSRIDExpectationsFactory extends AbstractExpectationsFactory ); } - /* - * (non-Javadoc) - * - * @seeorg.hibernatespatial.test.AbstractExpectationsFactory# - * createNativeDisjointStatement(com.vividsolutions.jts.geom.Geometry) - */ - @Override protected NativeSQLStatement createNativeDisjointStatement(Geometry geom) { return createNativeSQLStatementAllWKTParams( @@ -197,13 +126,6 @@ public class GeoDBNoSRIDExpectationsFactory extends AbstractExpectationsFactory return createNativeSQLStatement( "select t.id, (st_srid(t.geom) = " + srid + ") from GeomTest t where ST_SRID(t.geom) = " + srid ); } - /* - * (non-Javadoc) - * - * @seeorg.hibernatespatial.test.AbstractExpectationsFactory# - * createNativeDistanceStatement(com.vividsolutions.jts.geom.Geometry) - */ - @Override protected NativeSQLStatement createNativeDistanceStatement(Geometry geom) { return createNativeSQLStatementAllWKTParams( @@ -212,25 +134,11 @@ public class GeoDBNoSRIDExpectationsFactory extends AbstractExpectationsFactory ); } - /* - * (non-Javadoc) - * - * @seeorg.hibernatespatial.test.AbstractExpectationsFactory# - * createNativeEnvelopeStatement() - */ - @Override protected NativeSQLStatement createNativeEnvelopeStatement() { return createNativeSQLStatement( "select id, ST_Envelope(geom) from GEOMTEST" ); } - /* - * (non-Javadoc) - * - * @seeorg.hibernatespatial.test.AbstractExpectationsFactory# - * createNativeEqualsStatement(com.vividsolutions.jts.geom.Geometry) - */ - @Override protected NativeSQLStatement createNativeEqualsStatement(Geometry geom) { return createNativeSQLStatementAllWKTParams( @@ -239,13 +147,6 @@ public class GeoDBNoSRIDExpectationsFactory extends AbstractExpectationsFactory ); } - /* - * (non-Javadoc) - * - * @seeorg.hibernatespatial.test.AbstractExpectationsFactory# - * createNativeFilterStatement(com.vividsolutions.jts.geom.Geometry) - */ - @Override protected NativeSQLStatement createNativeFilterStatement(Geometry geom) { throw new UnsupportedOperationException( @@ -253,13 +154,6 @@ public class GeoDBNoSRIDExpectationsFactory extends AbstractExpectationsFactory ); } - /* - * (non-Javadoc) - * - * @seeorg.hibernatespatial.test.AbstractExpectationsFactory# - * createNativeGeomUnionStatement(com.vividsolutions.jts.geom.Geometry) - */ - @Override protected NativeSQLStatement createNativeGeomUnionStatement(Geometry geom) { throw new UnsupportedOperationException( @@ -267,25 +161,11 @@ public class GeoDBNoSRIDExpectationsFactory extends AbstractExpectationsFactory ); } - /* - * (non-Javadoc) - * - * @seeorg.hibernatespatial.test.AbstractExpectationsFactory# - * createNativeGeometryTypeStatement() - */ - @Override protected NativeSQLStatement createNativeGeometryTypeStatement() { return createNativeSQLStatement( "select id, GeometryType(geom) from GEOMTEST" ); } - /* - * (non-Javadoc) - * - * @seeorg.hibernatespatial.test.AbstractExpectationsFactory# - * createNativeIntersectionStatement(com.vividsolutions.jts.geom.Geometry) - */ - @Override protected NativeSQLStatement createNativeIntersectionStatement(Geometry geom) { throw new UnsupportedOperationException( @@ -293,13 +173,6 @@ public class GeoDBNoSRIDExpectationsFactory extends AbstractExpectationsFactory ); } - /* - * (non-Javadoc) - * - * @seeorg.hibernatespatial.test.AbstractExpectationsFactory# - * createNativeIntersectsStatement(com.vividsolutions.jts.geom.Geometry) - */ - @Override protected NativeSQLStatement createNativeIntersectsStatement(Geometry geom) { return createNativeSQLStatementAllWKTParams( @@ -308,13 +181,6 @@ public class GeoDBNoSRIDExpectationsFactory extends AbstractExpectationsFactory ); } - /* - * (non-Javadoc) - * - * @seeorg.hibernatespatial.test.AbstractExpectationsFactory# - * createNativeIsEmptyStatement() - */ - @Override protected NativeSQLStatement createNativeIsEmptyStatement() { return createNativeSQLStatement( "select id, ST_IsEmpty(geom) from GEOMTEST" ); @@ -325,25 +191,11 @@ public class GeoDBNoSRIDExpectationsFactory extends AbstractExpectationsFactory return createNativeSQLStatement( "select id, not ST_IsEmpty(geom) from GEOMTEST" ); } - /* - * (non-Javadoc) - * - * @seeorg.hibernatespatial.test.AbstractExpectationsFactory# - * createNativeIsSimpleStatement() - */ - @Override protected NativeSQLStatement createNativeIsSimpleStatement() { return createNativeSQLStatement( "select id, ST_IsSimple(geom) from GEOMTEST" ); } - /* - * (non-Javadoc) - * - * @seeorg.hibernatespatial.test.AbstractExpectationsFactory# - * createNativeOverlapsStatement(com.vividsolutions.jts.geom.Geometry) - */ - @Override protected NativeSQLStatement createNativeOverlapsStatement(Geometry geom) { return createNativeSQLStatementAllWKTParams( @@ -352,14 +204,6 @@ public class GeoDBNoSRIDExpectationsFactory extends AbstractExpectationsFactory ); } - /* - * (non-Javadoc) - * - * @seeorg.hibernatespatial.test.AbstractExpectationsFactory# - * createNativeRelateStatement(com.vividsolutions.jts.geom.Geometry, - * java.lang.String) - */ - @Override protected NativeSQLStatement createNativeRelateStatement(Geometry geom, String matrix) { @@ -386,13 +230,6 @@ public class GeoDBNoSRIDExpectationsFactory extends AbstractExpectationsFactory return createNativeSQLStatement( "select id, ST_SRID(geom) from GEOMTEST" ); } - /* - * (non-Javadoc) - * - * @seeorg.hibernatespatial.test.AbstractExpectationsFactory# - * createNativeSymDifferenceStatement(com.vividsolutions.jts.geom.Geometry) - */ - @Override protected NativeSQLStatement createNativeSymDifferenceStatement( Geometry geom) { @@ -401,13 +238,6 @@ public class GeoDBNoSRIDExpectationsFactory extends AbstractExpectationsFactory ); } - /* - * (non-Javadoc) - * - * @seeorg.hibernatespatial.test.AbstractExpectationsFactory# - * createNativeTouchesStatement(com.vividsolutions.jts.geom.Geometry) - */ - @Override protected NativeSQLStatement createNativeTouchesStatement(Geometry geom) { return createNativeSQLStatementAllWKTParams( @@ -416,13 +246,6 @@ public class GeoDBNoSRIDExpectationsFactory extends AbstractExpectationsFactory ); } - /* - * (non-Javadoc) - * - * @seeorg.hibernatespatial.test.AbstractExpectationsFactory# - * createNativeWithinStatement(com.vividsolutions.jts.geom.Geometry) - */ - @Override protected NativeSQLStatement createNativeWithinStatement( Geometry testPolygon) { @@ -432,17 +255,8 @@ public class GeoDBNoSRIDExpectationsFactory extends AbstractExpectationsFactory ); } - /* - * (non-Javadoc) - * - * @see - * org.hibernatespatial.test.AbstractExpectationsFactory#decode(java.lang - * .Object) - */ - @Override protected Geometry decode(Object o) { - return decoder.toJTS( o ); + return JTS.to( Wkb.fromWkb( ByteBuffer.from( (byte[]) o ) ) ); } - } diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/mysql/MySQLExpectationsFactory.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/mysql/MySQLExpectationsFactory.java index 091aa81044..271e142e78 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/mysql/MySQLExpectationsFactory.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/mysql/MySQLExpectationsFactory.java @@ -23,9 +23,11 @@ package org.hibernate.spatial.testing.dialects.mysql; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.Point; +import org.geolatte.geom.ByteBuffer; +import org.geolatte.geom.codec.Wkb; +import org.geolatte.geom.codec.WkbDecoder; +import org.geolatte.geom.jts.JTS; -import org.hibernate.spatial.JTSGeometryJavaTypeDescriptor; -import org.hibernate.spatial.dialect.mysql.MySQLGeometryValueExtractor; import org.hibernate.spatial.testing.AbstractExpectationsFactory; import org.hibernate.spatial.testing.DataSourceUtils; import org.hibernate.spatial.testing.NativeSQLStatement; @@ -39,8 +41,6 @@ import org.hibernate.spatial.testing.NativeSQLStatement; public class MySQLExpectationsFactory extends AbstractExpectationsFactory { - private final MySQLGeometryValueExtractor decoder = new MySQLGeometryValueExtractor( JTSGeometryJavaTypeDescriptor.INSTANCE); - public MySQLExpectationsFactory(DataSourceUtils dataSourceUtils) { super( dataSourceUtils ); } @@ -245,7 +245,12 @@ public class MySQLExpectationsFactory extends AbstractExpectationsFactory { } @Override - protected Geometry decode(Object o) { - return decoder.toJTS( o ); + protected Geometry decode(Object bytes) { + if ( bytes == null ) { + return null; + } + ByteBuffer buffer = ByteBuffer.from( (byte[])bytes ); + WkbDecoder decoder = Wkb.newDecoder( Wkb.Dialect.MYSQL_WKB ); + return JTS.to( decoder.decode( buffer ) ); } } diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/mysql/MySQLExpressionTemplate.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/mysql/MySQLExpressionTemplate.java index aa72ae4269..df4eb66766 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/mysql/MySQLExpressionTemplate.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/mysql/MySQLExpressionTemplate.java @@ -24,6 +24,7 @@ package org.hibernate.spatial.testing.dialects.mysql; import org.hibernate.spatial.testing.SQLExpressionTemplate; import org.hibernate.spatial.testing.TestDataElement; +import org.hibernate.spatial.testing.WktUtility; /** * This is the template for insert SQL statements into the geomtest test table for MySQL. @@ -35,12 +36,14 @@ public class MySQLExpressionTemplate implements SQLExpressionTemplate { final String SQL_TEMPLATE = "insert into geomtest (id, type, geom) values (%d, '%s', GeomFromText('%s', %d))"; public String toInsertSql(TestDataElement testDataElement) { + String wkt = WktUtility.getWkt( testDataElement.wkt ); + int srid = WktUtility.getSRID( testDataElement.wkt ); return String.format( SQL_TEMPLATE, testDataElement.id, testDataElement.type, - testDataElement.wkt, - testDataElement.srid + wkt, + srid ); } } diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/mysql/MySQLTestSupport.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/mysql/MySQLTestSupport.java index bd18d52f62..0e0e5f2285 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/mysql/MySQLTestSupport.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/mysql/MySQLTestSupport.java @@ -38,11 +38,8 @@ public class MySQLTestSupport extends TestSupport { @Override public TestData createTestData(BaseCoreFunctionalTestCase testcase) { - if ( testcase.getClass().getCanonicalName().contains( "TestSpatialFunctions" ) || - testcase.getClass().getCanonicalName().contains( "TestSpatialRestrictions" ) ) { - return TestData.fromFile( "mysql/test-mysql-functions-data-set.xml" ); - } - return TestData.fromFile( "test-data-set.xml" ); + return TestData.fromFile( "mysql/test-mysql-functions-data-set.xml" ); + } @Override diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/oracle/SDOTestDataElement.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/oracle/SDOTestDataElement.java index b6db035dd2..c5e00fee27 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/oracle/SDOTestDataElement.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/oracle/SDOTestDataElement.java @@ -35,8 +35,8 @@ public class SDOTestDataElement extends TestDataElement { public final String sdo; - public SDOTestDataElement(int id, String type, String wkt, int srid, String sdo) { - super( id, type, wkt, srid ); + public SDOTestDataElement(int id, String type, String wkt, String sdo) { + super( id, type, wkt); this.sdo = sdo; } diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/oracle/SDOTestDataReader.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/oracle/SDOTestDataReader.java index c404e3bae5..d4635c6853 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/oracle/SDOTestDataReader.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/oracle/SDOTestDataReader.java @@ -37,9 +37,8 @@ public class SDOTestDataReader extends TestDataReader { int id = Integer.valueOf( element.selectSingleNode( "id" ).getText() ); String type = element.selectSingleNode( "type" ).getText(); String wkt = element.selectSingleNode( "wkt" ).getText(); - int srid = Integer.valueOf( element.selectSingleNode( "srid" ).getText() ); String sdo = element.selectSingleNode( "sdo" ).getText(); - TestDataElement testDataElement = new SDOTestDataElement( id, type, wkt, srid, sdo ); + TestDataElement testDataElement = new SDOTestDataElement( id, type, wkt, sdo ); testDataElements.add( testDataElement ); } diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/postgis/PostgisExpectationsFactory.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/postgis/PostgisExpectationsFactory.java index 82d31b48dd..4033578d7e 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/postgis/PostgisExpectationsFactory.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/postgis/PostgisExpectationsFactory.java @@ -23,9 +23,14 @@ package org.hibernate.spatial.testing.dialects.postgis; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.Point; +import org.geolatte.geom.ByteBuffer; +import org.geolatte.geom.codec.Wkb; +import org.geolatte.geom.codec.WkbDecoder; +import org.geolatte.geom.jts.JTS; +import org.postgresql.util.PGobject; -import org.hibernate.spatial.JTSGeometryJavaTypeDescriptor; -import org.hibernate.spatial.dialect.postgis.PGGeometryValueExtractor; +import org.hibernate.spatial.Log; +import org.hibernate.spatial.LogFactory; import org.hibernate.spatial.testing.AbstractExpectationsFactory; import org.hibernate.spatial.testing.DataSourceUtils; import org.hibernate.spatial.testing.NativeSQLStatement; @@ -37,7 +42,8 @@ import org.hibernate.spatial.testing.NativeSQLStatement; */ public class PostgisExpectationsFactory extends AbstractExpectationsFactory { - private final PGGeometryValueExtractor decoder = new PGGeometryValueExtractor( JTSGeometryJavaTypeDescriptor.INSTANCE); + private static final Log LOG = LogFactory.make(); + public PostgisExpectationsFactory(DataSourceUtils utils) { super( utils ); @@ -245,9 +251,20 @@ public class PostgisExpectationsFactory extends AbstractExpectationsFactory { ); } + //remove redundancy with toGeometry function in PGGeometryTypeDescriptor @Override - protected Geometry decode(Object o) { - return decoder.toJTS( o ); + protected Geometry decode(Object object) { + ByteBuffer buffer = null; + if (object instanceof PGobject ) { + buffer = ByteBuffer.from( ( (PGobject) object ).getValue() ); + } else if ( object instanceof byte[] ) { + byte[] bytes = (byte[]) object; + ByteBuffer.from( bytes ); + } else { + throw new IllegalStateException( "Received object of type " + object.getClass().getCanonicalName() ); + } + WkbDecoder decoder = Wkb.newDecoder( Wkb.Dialect.POSTGIS_EWKB_1 ); + return JTS.to(decoder.decode( buffer)); } } diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/postgis/PostgisExpressionTemplate.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/postgis/PostgisExpressionTemplate.java index 1d7ff8df43..2779dfdf37 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/postgis/PostgisExpressionTemplate.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/postgis/PostgisExpressionTemplate.java @@ -31,15 +31,14 @@ import org.hibernate.spatial.testing.TestDataElement; */ public class PostgisExpressionTemplate implements SQLExpressionTemplate { - final String SQL_TEMPLATE = "insert into geomtest (id, type, geom) values (%d, '%s', GeomFromText('%s', %d))"; + final String SQL_TEMPLATE = "insert into geomtest (id, type, geom) values (%d, '%s', GeomFromText('%s'))"; public String toInsertSql(TestDataElement testDataElement) { return String.format( SQL_TEMPLATE, testDataElement.id, testDataElement.type, - testDataElement.wkt, - testDataElement.srid + testDataElement.wkt ); } } diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/sqlserver/SQLServerExpressionTemplate.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/sqlserver/SQLServerExpressionTemplate.java index a05aba74ed..4f452825e4 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/sqlserver/SQLServerExpressionTemplate.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/sqlserver/SQLServerExpressionTemplate.java @@ -23,6 +23,7 @@ package org.hibernate.spatial.testing.dialects.sqlserver; import org.hibernate.spatial.testing.SQLExpressionTemplate; import org.hibernate.spatial.testing.TestDataElement; +import org.hibernate.spatial.testing.WktUtility; /** * @author Karel Maesen, Geovise BVBA @@ -32,12 +33,14 @@ public class SQLServerExpressionTemplate implements SQLExpressionTemplate { final String SQL_TEMPLATE = "insert into geomtest (id, type, geom) values (%d, '%s', Geometry::STGeomFromText('%s', %d))"; public String toInsertSql(TestDataElement testDataElement) { + int srid = WktUtility.getSRID( testDataElement.wkt ); + String wkt = WktUtility.getWkt( testDataElement.wkt ); return String.format( SQL_TEMPLATE, testDataElement.id, testDataElement.type, - testDataElement.wkt, - testDataElement.srid + wkt, + srid ); } diff --git a/hibernate-spatial/src/test/resources/h2geodb/test-geodb-data-set.xml b/hibernate-spatial/src/test/resources/h2geodb/test-geodb-data-set.xml index 32ae0dea16..c5c764e8ee 100644 --- a/hibernate-spatial/src/test/resources/h2geodb/test-geodb-data-set.xml +++ b/hibernate-spatial/src/test/resources/h2geodb/test-geodb-data-set.xml @@ -10,60 +10,51 @@ In MySQL these are stored as null objects. 1 POINT - POINT(10 5) - 4326 + SRID=4326;POINT(10 5) 2 POINT - POINT(52.25 2.53) - 4326 + SRID=4326;POINT(52.25 2.53) 3 POINT - POINT(51 12) - 4326 + SRID=4326;POINT(51 12) 4 POINT - POINT(10.0 2.0) - 4326 + SRID=4326;POINT(10.0 2.0) 5 LINESTRING - LINESTRING(10.0 5.0, 20.0 15.0) - 4326 + SRID=4326;LINESTRING(10.0 5.0, 20.0 15.0) 6 LINESTRING - LINESTRING(10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0) - 4326 + SRID=4326;LINESTRING(10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0) 16 POLYGON - POLYGON( (0 0, 0 10, 10 10, 10 0, 0 0) ) - 4326 + SRID=4326;POLYGON( (0 0, 0 10, 10 10, 10 0, 0 0) ) 18 POLYGON - POLYGON( (0 0, 0 10, 10 10, 10 0, 0 0), (2 2, 2 5, 5 5,5 2, 2 2)) - 4326 + SRID=4326;POLYGON( (0 0, 0 10, 10 10, 10 0, 0 0), (2 2, 2 5, 5 5,5 2, 2 2)) 19 POLYGON - POLYGON( (110 110, 110 120, 120 120, 120 110, 110 110) ) - 4326 + SRID=4326;POLYGON( (110 110, 110 120, 120 120, 120 110, 110 110) ) diff --git a/hibernate-spatial/src/test/resources/hibernate.properties b/hibernate-spatial/src/test/resources/hibernate.properties index 857fcdbe35..0ef89ea6d7 100644 --- a/hibernate-spatial/src/test/resources/hibernate.properties +++ b/hibernate-spatial/src/test/resources/hibernate.properties @@ -26,14 +26,14 @@ hibernate.test.new_metadata_mappings = true hibernate.connection.pool_size 5 -hibernate.show_sql false +hibernate.show_sql true hibernate.max_fetch_depth 5 -#hibernate.dialect org.hibernate.dialect.H2Dialect -#hibernate.connection.driver_class org.h2.Driver -#hibernate.connection.url jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;MVCC=TRUE -#hibernate.connection.username sa +hibernate.dialect org.hibernate.dialect.H2Dialect +hibernate.connection.driver_class org.h2.Driver +hibernate.connection.url jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;MVCC=TRUE +hibernate.connection.username sa #hibernate.cache.region_prefix hibernate.test #hibernate.cache.region.factory_class org.hibernate.testing.cache.CachingRegionFactory @@ -50,19 +50,29 @@ hibernate.max_fetch_depth 5 #hibernate.connection.username hibbrtru #hibernate.connection.password hibbrtru -# +## Oracle 10g #hibernate.dialect org.hibernate.spatial.dialect.oracle.OracleSpatial10gDialect #hibernate.connection.driver_class oracle.jdbc.driver.OracleDriver #hibernate.connection.url jdbc:oracle:thin:@oracle.geovise.com/ORCL #hibernate.connection.username hbs #hibernate.connection.password hbs +## Oracle 11g +## +#hibernate.dialect org.hibernate.spatial.dialect.oracle.OracleSpatial10gDialect +#hibernate.connection.driver_class oracle.jdbc.driver.OracleDriver +#hibernate.connection.url jdbc:oracle:thin:@oracle11g.geovise.com:1521/orcl11g.geovise.com +#hibernate.connection.username HBS +#hibernate.connection.password HBS -hibernate.dialect org.hibernate.spatial.dialect.sqlserver.SqlServer2008SpatialDialect -hibernate.connection.driver_class com.microsoft.sqlserver.jdbc.SQLServerDriver -hibernate.connection.url jdbc:sqlserver://sqlserver.geovise.com:1433;databaseName=HBS -hibernate.connection.username hbs -hibernate.connection.password hbs + +## Sql Server 2008 +## +#hibernate.dialect org.hibernate.spatial.dialect.sqlserver.SqlServer2008SpatialDialect +#hibernate.connection.driver_class com.microsoft.sqlserver.jdbc.SQLServerDriver +#hibernate.connection.url jdbc:sqlserver://sqlserver.geovise.com:1433;databaseName=HBS +#hibernate.connection.username hbs +#hibernate.connection.password hbs ## diff --git a/hibernate-spatial/src/test/resources/mysql/test-mysql-functions-data-set.xml b/hibernate-spatial/src/test/resources/mysql/test-mysql-functions-data-set.xml index 8d2c81ff4a..3d94dbef00 100644 --- a/hibernate-spatial/src/test/resources/mysql/test-mysql-functions-data-set.xml +++ b/hibernate-spatial/src/test/resources/mysql/test-mysql-functions-data-set.xml @@ -9,135 +9,116 @@ In MySQL these are stored as null objects. 1 POINT - POINT(10 5) - 4326 + SRID=4326;POINT(10 5) 2 POINT - POINT(52.25 2.53) - 4326 + SRID=4326;POINT(52.25 2.53) 3 POINT - POINT(51 12) - 4326 + SRID=4326;POINT(51 12) 4 POINT - POINT(10.0 2.0) - 4326 + SRID=4326;POINT(10.0 2.0) 5 LINESTRING - LINESTRING(10.0 5.0, 20.0 15.0) - 4326 + SRID=4326;LINESTRING(10.0 5.0, 20.0 15.0) 6 LINESTRING - LINESTRING(10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0) - 4326 + SRID=4326;LINESTRING(10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0) 11 MULTILINESTRING - MULTILINESTRING((10.0 5.0, 20.0 15.0),( 25.0 30.0, 30.0 20.0)) - 4326 + SRID=4326;MULTILINESTRING((10.0 5.0, 20.0 15.0),( 25.0 30.0, 30.0 20.0)) 12 MULTILINESTRING - MULTILINESTRING((10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0), (40.0 20.0, 42.0 18.0, 43.0 16.0, 40 14.0)) + SRID=4326;MULTILINESTRING((10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0), (40.0 20.0, 42.0 18.0, 43.0 16.0, 40 14.0)) - 4326 16 POLYGON - POLYGON( (0 0, 0 10, 10 10, 10 0, 0 0) ) - 4326 + SRID=4326;POLYGON( (0 0, 0 10, 10 10, 10 0, 0 0) ) 18 POLYGON - POLYGON( (0 0, 0 10, 10 10, 10 0, 0 0), (2 2, 2 5, 5 5,5 2, 2 2)) - 4326 + SRID=4326;POLYGON( (0 0, 0 10, 10 10, 10 0, 0 0), (2 2, 2 5, 5 5,5 2, 2 2)) 19 POLYGON - POLYGON( (110 110, 110 120, 120 120, 120 110, 110 110) ) - 4326 + SRID=4326;POLYGON( (110 110, 110 120, 120 120, 120 110, 110 110) ) 20 MULTIPOLYGON - MULTIPOLYGON( ((10 20, 30 40, 44 50, 10 20)), ((105 100, 120 140, 130 134, 105 100)) ) - 4326 + SRID=4326;MULTIPOLYGON( ((10 20, 30 40, 44 50, 10 20)), ((105 100, 120 140, 130 134, 105 100)) ) 22 MULTIPOLYGON - MULTIPOLYGON(( (0 0, 0 50, 50 50, 50 0, 0 0), (10 10, 10 20, 20 20, 20 10, 10 10) ),((105 100, 120 140, 130 + SRID=4326;MULTIPOLYGON(( (0 0, 0 50, 50 50, 50 0, 0 0), (10 10, 10 20, 20 20, 20 10, 10 10) ),((105 100, 120 140, 130 134, 105 100)) ) - 4326 25 MULTIPOINT - MULTIPOINT(21 2, 25 5, 30 3) - 4326 + SRID=4326;MULTIPOINT(21 2, 25 5, 30 3) 26 MULTIPOINT - MULTIPOINT(21 2) - 4326 + SRID=4326;MULTIPOINT(21 2) 30 GEOMETRYCOLLECTION - GEOMETRYCOLLECTION(POINT(4 0), LINESTRING(4 2, 5 3)) - 4326 + SRID=4326;GEOMETRYCOLLECTION(POINT(4 0), LINESTRING(4 2, 5 3)) 31 GEOMETRYCOLLECTION - GEOMETRYCOLLECTION(POINT(4 0), LINESTRING(4 2, 5 3), POLYGON((0 0, 3 0, 3 3,0 3, 0 0))) - 4326 + SRID=4326;GEOMETRYCOLLECTION(POINT(4 0), LINESTRING(4 2, 5 3), POLYGON((0 0, 3 0, 3 3,0 3, 0 0))) 32 GEOMETRYCOLLECTION - GEOMETRYCOLLECTION(POINT(4 0), LINESTRING(4 2, 5 3), POLYGON((0 0, 3 0, 3 3,0 3, 0 0),(1 1, 2 1, 2 2, 1 2, + SRID=4326;GEOMETRYCOLLECTION(POINT(4 0), LINESTRING(4 2, 5 3), POLYGON((0 0, 3 0, 3 3,0 3, 0 0),(1 1, 2 1, 2 2, 1 2, 1 1))) - 4326 33 GEOMETRYCOLLECTION - GEOMETRYCOLLECTION( MULTIPOINT(21 2, 25 5, 30 3), MULTIPOLYGON( ((10 20, 30 40, 44 50, 10 20)), ((105 100, + SRID=4326;GEOMETRYCOLLECTION( MULTIPOINT(21 2, 25 5, 30 3), MULTIPOLYGON( ((10 20, 30 40, 44 50, 10 20)), ((105 100, 120 140, 130 134, 105 100)) ), MULTILINESTRING((10.0 5.0, 20.0 15.0),( 25.0 30.0, 30.0 20.0))) - 4326 diff --git a/hibernate-spatial/src/test/resources/oracle10g/test-sdo-geometry-data-set-2D.xml b/hibernate-spatial/src/test/resources/oracle10g/test-sdo-geometry-data-set-2D.xml index 11d5732877..28c28aa686 100644 --- a/hibernate-spatial/src/test/resources/oracle10g/test-sdo-geometry-data-set-2D.xml +++ b/hibernate-spatial/src/test/resources/oracle10g/test-sdo-geometry-data-set-2D.xml @@ -35,32 +35,28 @@ 1 POINT SDO_GEOMETRY(2001, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,1,1), SDO_ORDINATE_ARRAY(10.0, 5.0)) - POINT(10 5) - 4326 + SRID=4326;POINT(10 5) 2 POINT SDO_GEOMETRY(2001, 4326, SDO_POINT_TYPE(52.25, 2.53, NULL), NULL, NULL) - POINT(52.25 2.53) - 4326 + SRID=4326;POINT(52.25 2.53) 5 LINESTRING - LINESTRING(10.0 5.0, 20.0 15.0) - 4326 + SRID=4326;LINESTRING(10.0 5.0, 20.0 15.0) SDO_GEOMETRY(2002, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,2,1), SDO_ORDINATE_ARRAY(10.0, 5.0, 20.0, 15.0)) 6 LINESTRING - LINESTRING(10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0) - 4326 + SRID=4326;LINESTRING(10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0) SDO_GEOMETRY(2002, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,2,1), SDO_ORDINATE_ARRAY(10.0, 5.0, 20.0, 15.0, 30.3, 22.4, 10.0, 30.0 )) @@ -70,8 +66,7 @@ 11 MULTILINESTRING - MULTILINESTRING((10.0 5.0, 20.0 15.0),( 25.0 30.0, 30.0 20.0)) - 4326 + SRID=4326;MULTILINESTRING((10.0 5.0, 20.0 15.0),( 25.0 30.0, 30.0 20.0)) SDO_GEOMETRY(2006, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,2,1,5,2,1), SDO_ORDINATE_ARRAY(10.0, 5.0, 20.0, 15.0,25.0,30.0, 30.0,20.0)) @@ -80,9 +75,8 @@ 12 MULTILINESTRING - MULTILINESTRING((10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0), (40.0 20.0, 42.0 18.0, 43.0 16.0, 40 14.0)) + SRID=4326;MULTILINESTRING((10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0), (40.0 20.0, 42.0 18.0, 43.0 16.0, 40 14.0)) - 4326 SDO_GEOMETRY(2006, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,2,1,9,2,1), SDO_ORDINATE_ARRAY(10.0,5.0,20.0,15.0,30.3,22.4,10,30.0,40.0,20.0,42.0,18.0,43.0,16.0,40,14.0)) @@ -91,8 +85,7 @@ 16 POLYGON - POLYGON( (0 0, 0 10, 10 10, 10 0, 0 0) ) - 4326 + SRID=4326;POLYGON( (0 0, 10 0, 10 10, 0 10, 0 0) ) SDO_GEOMETRY(2003, 4326, NULL, SDO_ELEM_INFO_ARRAY(1, 1003, 1), SDO_ORDINATE_ARRAY(0,0,0,10,10,10,10,0,0,0)) @@ -101,18 +94,16 @@ 18 POLYGON - POLYGON( (0 0, 0 10, 10 10, 10 0, 0 0), (2 2, 2 5, 5 5,5 2, 2 2)) + SRID=4326;POLYGON( (0 0, 10 0, 10 10, 0 10, 0 0), (2 2, 2 5, 5 5,5 2, 2 2)) SDO_GEOMETRY(2003, 4326, NULL, SDO_ELEM_INFO_ARRAY(1, 1003, 1, 11, 2003, 1), SDO_ORDINATE_ARRAY(0, 0, 0, 10, 10, 10, 10, 0, 0, 0, 2, 2, 2, 5, 5, 5, 5, 2, 2, 2)) - 4326 19 POLYGON - POLYGON( (110 110, 110 120, 120 120, 120 110, 110 110) ) - 4326 + SRID=4326;POLYGON( (110 110, 120 110, 120 120, 110 120, 110 110) ) SDO_GEOMETRY(2003, 4326, NULL, SDO_ELEM_INFO_ARRAY(1, 1003, 1), SDO_ORDINATE_ARRAY(110,110,110,120,120,120,120,110,110,110)) @@ -121,8 +112,7 @@ 20 MULTIPOLYGON - MULTIPOLYGON( ((10 20, 30 40, 44 50, 10 20)), ((105 100, 120 140, 130 134, 105 100)) ) - 4326 + SRID=4326;MULTIPOLYGON( ((10 20, 44 50, 30 40, 10 20)), ((105 100, 130 134, 120 140, 105 100)) ) SDO_GEOMETRY(2007, 4326, NULL, SDO_ELEM_INFO_ARRAY(1, 1003, 1, 9, 1003, 1), SDO_ORDINATE_ARRAY(10, 20, 30, 40, 44, 50, 10, 20, 105, 100, 120, 140, 130, 134, 105, 100)) diff --git a/hibernate-spatial/src/test/resources/oracle10g/test-sdo-geometry-data-set.xml b/hibernate-spatial/src/test/resources/oracle10g/test-sdo-geometry-data-set.xml index 92b5e3277b..075d639208 100644 --- a/hibernate-spatial/src/test/resources/oracle10g/test-sdo-geometry-data-set.xml +++ b/hibernate-spatial/src/test/resources/oracle10g/test-sdo-geometry-data-set.xml @@ -32,45 +32,39 @@ 1 POINT SDO_GEOMETRY(2001, 0, SDO_POINT_TYPE(10, 5, NULL), NULL, NULL) - POINT(10 5) - 4326 + SRID=4326;POINT(10 5) 2 POINT SDO_GEOMETRY(2001, 4326, SDO_POINT_TYPE(52.25, 2.53, NULL), NULL, NULL) - POINT(52.25 2.53) - 4326 + SRID=4326;POINT(52.25 2.53) 3 POINT SDO_GEOMETRY(3001, 31370, SDO_POINT_TYPE(150000, 200000, 500), NULL, NULL) - POINT(150000 200000 500) - 4326 + SRID=4326;POINT(150000 200000 500) 4 POINT SDO_GEOMETRY(4401, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,1,1), SDO_ORDINATE_ARRAY(10.0, 2.0, 1.0, 3.0)) - POINT(10.0 2.0 1.0 3.0) - 4326 + SRID=4326;POINT(10.0 2.0 1.0 3.0) 5 LINESTRING - LINESTRING(10.0 5.0, 20.0 15.0) - 4326 + SRID=4326;LINESTRING(10.0 5.0, 20.0 15.0) SDO_GEOMETRY(2002, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,2,1), SDO_ORDINATE_ARRAY(10.0, 5.0, 20.0, 15.0)) 6 LINESTRING - LINESTRING(10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0) - 4326 + SRID=4326;LINESTRING(10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0) SDO_GEOMETRY(2002, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,2,1), SDO_ORDINATE_ARRAY(10.0, 5.0, 20.0, 15.0, 30.3, 22.4, 10.0, 30.0 )) @@ -79,18 +73,16 @@ 7 LINESTRING - LINESTRING(10.0 5.0 0.0, 20.0 15.0 3.0) + SRID=4326;LINESTRING(10.0 5.0 0.0, 20.0 15.0 3.0) SDO_GEOMETRY(3002, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,2,1), SDO_ORDINATE_ARRAY(10.0, 5.0, 0.0, 20.0, 15, 3.0 )) - 4326 8 LINESTRING - LINESTRING(10.0 5.0 0.0 0.0, 20.0 15.0 3.0 1.0) - 4326 + SRID=4326;LINESTRING(10.0 5.0 0.0 0.0, 20.0 15.0 3.0 1.0) SDO_GEOMETRY(4402, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,2,1), SDO_ORDINATE_ARRAY(10.0, 5.0, 0.0, 0.0, 20.0, 15, 3.0, 1.0)) @@ -99,8 +91,7 @@ 9 LINESTRING - LINESTRING(10.0 5.0 1, 20.0 15.0 2, 30.3 22.4 5, 10 30.0 2) - 4326 + SRID=4326;LINESTRING(10.0 5.0 1, 20.0 15.0 2, 30.3 22.4 5, 10 30.0 2) SDO_GEOMETRY(3002, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,2,1), SDO_ORDINATE_ARRAY(10.0, 5.0, 1.0,20.0, 15, 2.0, 30.3, 22.4, 5.0, 10.0, 30.0, 2.0)) @@ -109,8 +100,7 @@ 10 LINESTRING - LINESTRING(10.0 5.0 1 1, 20.0 15.0 2 3, 30.3 22.4 5 10, 10 30.0 2 12) - 4326 + SRID=4326;LINESTRING(10.0 5.0 1 1, 20.0 15.0 2 3, 30.3 22.4 5 10, 10 30.0 2 12) SDO_GEOMETRY(4402, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,2,1), SDO_ORDINATE_ARRAY(10.0,5.0,1,1, 20.0, 15.0, 2, 3, 30.3, 22.4, 5, 10, 10, 30.0, 2, 12)) @@ -119,8 +109,7 @@ 11 MULTILINESTRING - MULTILINESTRING((10.0 5.0, 20.0 15.0),( 25.0 30.0, 30.0 20.0)) - 4326 + SRID=4326;MULTILINESTRING((10.0 5.0, 20.0 15.0),( 25.0 30.0, 30.0 20.0)) SDO_GEOMETRY(2006, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,2,1,5,2,1), SDO_ORDINATE_ARRAY(10.0, 5.0, 20.0, 15.0,25.0,30.0, 30.0,20.0)) @@ -129,9 +118,8 @@ 12 MULTILINESTRING - MULTILINESTRING((10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0), (40.0 20.0, 42.0 18.0, 43.0 16.0, 40 14.0)) + SRID=4326;MULTILINESTRING((10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0), (40.0 20.0, 42.0 18.0, 43.0 16.0, 40 14.0)) - 4326 SDO_GEOMETRY(2006, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,2,1,9,2,1), SDO_ORDINATE_ARRAY(10.0,5.0,20.0,15.0,30.3,22.4,10,30.0,40.0,20.0,42.0,18.0,43.0,16.0,40,14.0)) @@ -139,11 +127,10 @@ 13 - MULTILINESTRING + SRID=4326;MULTILINESTRING MULTILINESTRING((10.0 5.0 1.0, 20.0 15.0 2.0, 30.3 22.4 1.0, 10 30.0 1.0),(40.0 20.0 0.0, 42.0 18.0 1.0, 43.0 16.0 2.0, 40 14.0 3.0)) - 4326 SDO_GEOMETRY(3006, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,2,1,13,2,1), SDO_ORDINATE_ARRAY(10.0,5.0,1.0,20.0,15.0,2.0,30.3,22.4,1.0,10,30.0,1.0,40.0,20.0,0.0,42.0,18.0,1.0,43.0,16.0,2.0,40,14.0,3.0)) @@ -152,10 +139,9 @@ 14 MULTILINESTRING - MULTILINESTRING((10.0 5.0 1.0 0.0, 20.0 15.0 2.0 0.0, 30.3 22.4 1.0 1.0, 10 30.0 1.0 2.0),(40.0 20.0 0.0 + SRID=4326;MULTILINESTRING((10.0 5.0 1.0 0.0, 20.0 15.0 2.0 0.0, 30.3 22.4 1.0 1.0, 10 30.0 1.0 2.0),(40.0 20.0 0.0 3.0, 42.0 18.0 1.0 4.0, 43.0 16.0 2.0 5.0, 40 14.0 3.0 6.0)) - 4326 SDO_GEOMETRY(4406, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,2,1,17,2,1), SDO_ORDINATE_ARRAY(10.0,5.0,1.0,0.0,20.0,15.0,2.0,0.0,30.3,22.4,1.0,1.0,10,30.0,1.0,2.0,40.0,20.0,0.0,3.0,42.0,18.0,1.0,4.0,43.0,16.0,2.0,5.0,40,14.0,3.0,6.0)) @@ -164,8 +150,7 @@ 15 MULTILINESTRING - MULTILINESTRING((10.0 5.0 1.0 0.0, 20.0 15.0 2.0 0.0, 30.3 22.4 1.0 1.0, 10 30.0 1.0 2.0)) - 4326 + SRID=4326;MULTILINESTRING((10.0 5.0 1.0 0.0, 20.0 15.0 2.0 0.0, 30.3 22.4 1.0 1.0, 10 30.0 1.0 2.0)) SDO_GEOMETRY(4406, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,2,1), SDO_ORDINATE_ARRAY(10.0,5.0,1.0,0.0,20.0,15.0,2.0,0.0,30.3,22.4,1.0,1.0,10,30.0,1.0,2.0)) @@ -175,8 +160,7 @@ 16 POLYGON - POLYGON( (0 0, 0 10, 10 10, 10 0, 0 0) ) - 4326 + SRID=4326;POLYGON( (0 0, 0 10, 10 10, 10 0, 0 0) ) SDO_GEOMETRY(2003, 4326, NULL, SDO_ELEM_INFO_ARRAY(1, 1003, 1), SDO_ORDINATE_ARRAY(0,0,0,10,10,10,10,0,0,0)) @@ -186,8 +170,7 @@ 17 POLYGON - POLYGON( (0 0 0, 0 10 1, 10 10 1, 10 0 1, 0 0 0) ) - 4326 + SRID=4326;POLYGON( (0 0 0, 0 10 1, 10 10 1, 10 0 1, 0 0 0) ) SDO_GEOMETRY(3003, 4326, NULL, SDO_ELEM_INFO_ARRAY(1, 1003, 1), SDO_ORDINATE_ARRAY(0,0,0,0,10,1,10,10,1,10,0,1,0,0,0)) @@ -195,17 +178,15 @@ 18 POLYGON - POLYGON( (0 0, 0 10, 10 10, 10 0, 0 0), (2 2, 2 5, 5 5,5 2, 2 2)) + SRID=4326;POLYGON( (0 0, 0 10, 10 10, 10 0, 0 0), (2 2, 2 5, 5 5,5 2, 2 2)) SDO_GEOMETRY(2003, 4326, NULL, SDO_ELEM_INFO_ARRAY(1, 1003, 1, 11, 2003, 1), SDO_ORDINATE_ARRAY(0, 0, 0, 10, 10, 10, 10, 0, 0, 0, 2, 2, 2, 5, 5, 5, 5, 2, 2, 2)) - 4326 19 POLYGON - POLYGON( (110 110, 110 120, 120 120, 120 110, 110 110) ) - 4326 + SRID=4326;POLYGON( (110 110, 110 120, 120 120, 120 110, 110 110) ) SDO_GEOMETRY(2003, 4326, NULL, SDO_ELEM_INFO_ARRAY(1, 1003, 1), SDO_ORDINATE_ARRAY(110,110,110,120,120,120,120,110,110,110)) @@ -214,8 +195,7 @@ 20 MULTIPOLYGON - MULTIPOLYGON( ((10 20, 30 40, 44 50, 10 20)), ((105 100, 120 140, 130 134, 105 100)) ) - 4326 + SRID=4326;MULTIPOLYGON( ((10 20, 30 40, 44 50, 10 20)), ((105 100, 120 140, 130 134, 105 100)) ) SDO_GEOMETRY(2007, 4326, NULL, SDO_ELEM_INFO_ARRAY(1, 1003, 1, 9, 1003, 1), SDO_ORDINATE_ARRAY(10, 20, 30, 40, 44, 50, 10, 20, 105, 100, 120, 140, 130, 134, 105, 100)) @@ -223,9 +203,8 @@ 21 MULTIPOLYGON - MULTIPOLYGON( ((10 20 1, 30 40 2, 44 50 2, 10 20 1)), ((105 100 0, 120 140 10, 130 134 20, 105 100 0)) ) + SRID=4326;MULTIPOLYGON( ((10 20 1, 30 40 2, 44 50 2, 10 20 1)), ((105 100 0, 120 140 10, 130 134 20, 105 100 0)) ) - 4326 SDO_GEOMETRY(3007, 4326, NULL, SDO_ELEM_INFO_ARRAY(1, 1003, 1, 13, 1003, 1), SDO_ORDINATE_ARRAY(10,20,1,30,40,2,44,50,2,10,20,1,105,100,0,120,140,10,130,134,20,105,100,0)) @@ -233,43 +212,38 @@ 22 MULTIPOLYGON - MULTIPOLYGON(( (0 0, 0 50, 50 50, 50 0, 0 0), (10 10, 10 20, 20 20, 20 10, 10 10) ),((105 100, 120 140, 130 + SRID=4326;MULTIPOLYGON(( (0 0, 0 50, 50 50, 50 0, 0 0), (10 10, 10 20, 20 20, 20 10, 10 10) ),((105 100, 120 140, 130 134, 105 100))) SDO_GEOMETRY(2007, 4326, NULL, SDO_ELEM_INFO_ARRAY(1, 1003, 1, 11, 2003, 1, 21, 1003, 1), SDO_ORDINATE_ARRAY(0, 0, 0, 50, 50, 50, 50, 0, 0, 0, 10, 10, 10, 20, 20, 20, 20, 10, 10, 10, 105, 100, 120, 140, 130, 134, 105, 100)) - 4326 25 MULTIPOINT - MULTIPOINT(21 2, 25 5, 30 3) - 4326 + SRID=4326;MULTIPOINT(21 2, 25 5, 30 3) SDO_GEOMETRY(2005, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,1,1), SDO_ORDINATE_ARRAY(21,2,25,5,30,3)) 26 MULTIPOINT - MULTIPOINT(21 2) - 4326 + SRID=4326;MULTIPOINT(21 2) SDO_GEOMETRY(2005, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,1,1), SDO_ORDINATE_ARRAY(21,2)) 27 MULTIPOINT - MULTIPOINT(21 2 1, 25 5 2, 30 3 5) - 4326 + SRID=4326;MULTIPOINT(21 2 1, 25 5 2, 30 3 5) SDO_GEOMETRY(3005, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,1,1), SDO_ORDINATE_ARRAY(21,2,1,25,5,2,30,3,5)) 28 MULTIPOINT - MULTIPOINT(21 2 1 0, 25 5 2 4, 30 3 5 2) - 4326 + SRID=4326;MULTIPOINT(21 2 1 0, 25 5 2 4, 30 3 5 2) SDO_GEOMETRY(4405, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,1,1), SDO_ORDINATE_ARRAY(21,2,1,0,25,5,2,4,30,3,5,2)) diff --git a/hibernate-spatial/src/test/resources/postgis-functions-test.xml b/hibernate-spatial/src/test/resources/postgis-functions-test.xml index 5d09dd0829..44e869cacf 100644 --- a/hibernate-spatial/src/test/resources/postgis-functions-test.xml +++ b/hibernate-spatial/src/test/resources/postgis-functions-test.xml @@ -3,75 +3,64 @@ 1 POINT - POINT(10 5) - 4326 + SRID=4326;POINT(10 5) 2 POINT - POINT(79 79) - 4326 + SRID=4326;POINT(79 79) 3 POINT - POINT(50 50) - 4326 + SRID=4326;POINT(50 50) 4 POINT - POINT(10 20) - 4326 + SRID=4326;POINT(10 20) 5 POINT - POINT(-4 -5) - 4326 + SRID=4326;POINT(-4 -5) 6 LINESTRING - LINESTRING(10.0 5.0, 20.0 15.0) - 4326 + SRID=4326;LINESTRING(10.0 5.0, 20.0 15.0) 7 LINESTRING - LINESTRING(10.0 5.0 1, 20.0 15.0 2, 30.3 22.4 5, 10 30.0 2) - 4326 + SRID=4326;LINESTRING(10.0 5.0 1, 20.0 15.0 2, 30.3 22.4 5, 10 30.0 2) 8 LINESTRING - LINESTRING(10.0 5.0 1 1, 20.0 15.0 2 3, 30.3 22.4 5 10, 10 30.0 2 12) - 4326 + SRID=4326;LINESTRING(10.0 5.0 1 1, 20.0 15.0 2 3, 30.3 22.4 5 10, 10 30.0 2 12) 9 MULTILINESTRING - MULTILINESTRING((10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0), (40.0 20.0, 42.0 18.0, 43.0 16.0, 40 14.0)) + SRID=4326;MULTILINESTRING((10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0), (40.0 20.0, 42.0 18.0, 43.0 16.0, 40 14.0)) - 4326 10 POLYGON - POLYGON( (0 0, 0 10, 10 10, 10 0, 0 0) ) - 4326 + SRID=4326;POLYGON( (0 0, 0 10, 10 10, 10 0, 0 0) ) 11 MULTIPOLYGON - MULTIPOLYGON( ((10 20, 30 40, 44 50, 10 20)), ((15 10, 12 14, 13 13, 15 10)) ) - 4326 + SRID=4326;MULTIPOLYGON( ((10 20, 30 40, 44 50, 10 20)), ((15 10, 12 14, 13 13, 15 10)) ) diff --git a/hibernate-spatial/src/test/resources/test-data-set.xml b/hibernate-spatial/src/test/resources/test-data-set.xml index 93464f5e20..7ce4cce650 100644 --- a/hibernate-spatial/src/test/resources/test-data-set.xml +++ b/hibernate-spatial/src/test/resources/test-data-set.xml @@ -3,295 +3,251 @@ 1 POINT POINT(10 5) - 0 2 POINT - POINT(52.25 2.53) - 4326 + SRID=4326;POINT(52.25 2.53) 3 POINT - POINT(150000 200000) - 31370 + SRID=31370;POINT(150000 200000) 4 POINT - POINT(10.0 2.0 1.0 3.0) - 4326 + SRID=4326;POINT(10.0 2.0 1.0 3.0) 5 LINESTRING - LINESTRING(10.0 5.0, 20.0 15.0) - 4326 + SRID=4326;LINESTRING(10.0 5.0, 20.0 15.0) 6 LINESTRING - LINESTRING(10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0) - 4326 + SRID=4326;LINESTRING(10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0) 7 LINESTRING - LINESTRING(10.0 5.0 0.0, 20.0 15.0 3.0) - 4326 + SRID=4326;LINESTRING(10.0 5.0 0.0, 20.0 15.0 3.0) 8 LINESTRING - LINESTRING(10.0 5.0 0.0 0.0, 20.0 15.0 3.0 1.0) - 4326 + SRID=4326;LINESTRING(10.0 5.0 0.0 0.0, 20.0 15.0 3.0 1.0) 9 LINESTRING - LINESTRING(10.0 5.0 1, 20.0 15.0 2, 30.3 22.4 5, 10 30.0 2) - 4326 + SRID=4326;LINESTRING(10.0 5.0 1, 20.0 15.0 2, 30.3 22.4 5, 10 30.0 2) 10 LINESTRING - LINESTRING(10.0 5.0 1 1, 20.0 15.0 2 3, 30.3 22.4 5 10, 10 30.0 2 12) - 4326 + SRID=4326;LINESTRING(10.0 5.0 1 1, 20.0 15.0 2 3, 30.3 22.4 5 10, 10 30.0 2 12) 11 MULTILINESTRING - MULTILINESTRING((10.0 5.0, 20.0 15.0),( 25.0 30.0, 30.0 20.0)) - 4326 + SRID=4326;MULTILINESTRING((10.0 5.0, 20.0 15.0),( 25.0 30.0, 30.0 20.0)) 12 MULTILINESTRING - MULTILINESTRING((10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0), (40.0 20.0, 42.0 18.0, 43.0 16.0, 40 14.0)) + SRID=4326;MULTILINESTRING((10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0), (40.0 20.0, 42.0 18.0, 43.0 16.0, 40 14.0)) - 4326 13 MULTILINESTRING - MULTILINESTRING((10.0 5.0 1.0, 20.0 15.0 2.0, 30.3 22.4 1.0, 10 30.0 1.0),(40.0 20.0 0.0, 42.0 18.0 1.0, + SRID=4326;MULTILINESTRING((10.0 5.0 1.0, 20.0 15.0 2.0, 30.3 22.4 1.0, 10 30.0 1.0),(40.0 20.0 0.0, 42.0 18.0 1.0, 43.0 16.0 2.0, 40 14.0 3.0)) - 4326 14 MULTILINESTRING - MULTILINESTRING((10.0 5.0 1.0 0.0, 20.0 15.0 2.0 0.0, 30.3 22.4 1.0 1.0, 10 30.0 1.0 2.0),(40.0 20.0 0.0 + SRID=4326;MULTILINESTRING((10.0 5.0 1.0 0.0, 20.0 15.0 2.0 0.0, 30.3 22.4 1.0 1.0, 10 30.0 1.0 2.0),(40.0 20.0 0.0 3.0, 42.0 18.0 1.0 4.0, 43.0 16.0 2.0 5.0, 40 14.0 3.0 6.0)) - 4326 15 MULTILINESTRING - MULTILINESTRING((10.0 5.0 1.0 0.0, 20.0 15.0 2.0 0.0, 30.3 22.4 1.0 1.0, 10 30.0 1.0 2.0)) - 4326 + SRID=4326;MULTILINESTRING((10.0 5.0 1.0 0.0, 20.0 15.0 2.0 0.0, 30.3 22.4 1.0 1.0, 10 30.0 1.0 2.0)) 16 POLYGON - POLYGON( (0 0, 0 10, 10 10, 10 0, 0 0) ) - 4326 + SRID=4326;POLYGON( (0 0, 0 10, 10 10, 10 0, 0 0) ) 17 POLYGON - POLYGON( (0 0 0, 0 10 1, 10 10 1, 10 0 1, 0 0 0) ) - 4326 + SRID=4326;POLYGON( (0 0 0, 0 10 1, 10 10 1, 10 0 1, 0 0 0) ) 18 POLYGON - POLYGON( (0 0, 0 10, 10 10, 10 0, 0 0), (2 2, 2 5, 5 5,5 2, 2 2)) - 4326 + SRID=4326;POLYGON( (0 0, 0 10, 10 10, 10 0, 0 0), (2 2, 2 5, 5 5,5 2, 2 2)) 19 POLYGON - POLYGON( (110 110, 110 120, 120 120, 120 110, 110 110) ) - 4326 + SRID=4326;POLYGON( (110 110, 110 120, 120 120, 120 110, 110 110) ) 20 MULTIPOLYGON - MULTIPOLYGON( ((10 20, 30 40, 44 50, 10 20)), ((105 100, 120 140, 130 134, 105 100)) ) - 4326 + SRID=4326;MULTIPOLYGON( ((10 20, 30 40, 44 50, 10 20)), ((105 100, 120 140, 130 134, 105 100)) ) 21 MULTIPOLYGON - MULTIPOLYGON( ((10 20 1, 30 40 2, 44 50 2, 10 20 1)), ((105 100 0, 120 140 10, 130 134 20, 105 100 0)) ) + SRID=4326;MULTIPOLYGON( ((10 20 1, 30 40 2, 44 50 2, 10 20 1)), ((105 100 0, 120 140 10, 130 134 20, 105 100 0)) ) - 4326 22 MULTIPOLYGON - MULTIPOLYGON(( (0 0, 0 50, 50 50, 50 0, 0 0), (10 10, 10 20, 20 20, 20 10, 10 10) ),((105 100, 120 140, 130 + SRID=4326;MULTIPOLYGON(( (0 0, 0 50, 50 50, 50 0, 0 0), (10 10, 10 20, 20 20, 20 10, 10 10) ),((105 100, 120 140, 130 134, 105 100)) ) - 4326 25 MULTIPOINT - MULTIPOINT(21 2, 25 5, 30 3) - 4326 + SRID=4326;MULTIPOINT(21 2, 25 5, 30 3) 26 MULTIPOINT - MULTIPOINT(21 2) - 4326 + SRID=4326;MULTIPOINT(21 2) 27 MULTIPOINT - MULTIPOINT(21 2 1, 25 5 2, 30 3 5) - 4326 + SRID=4326;MULTIPOINT(21 2 1, 25 5 2, 30 3 5) 28 MULTIPOINT - MULTIPOINT(21 2 1 0, 25 5 2 4, 30 3 5 2) - 4326 + SRID=4326;MULTIPOINT(21 2 1 0, 25 5 2 4, 30 3 5 2) 30 GEOMETRYCOLLECTION - GEOMETRYCOLLECTION(POINT(4 0), LINESTRING(4 2, 5 3)) - 4326 + SRID=4326;GEOMETRYCOLLECTION(POINT(4 0), LINESTRING(4 2, 5 3)) 31 GEOMETRYCOLLECTION - GEOMETRYCOLLECTION(POINT(4 0), LINESTRING(4 2, 5 3), POLYGON((0 0, 3 0, 3 3,0 3, 0 0))) - 4326 + SRID=4326;GEOMETRYCOLLECTION(POINT(4 0), LINESTRING(4 2, 5 3), POLYGON((0 0, 3 0, 3 3,0 3, 0 0))) 32 GEOMETRYCOLLECTION - GEOMETRYCOLLECTION(POINT(4 0), LINESTRING(4 2, 5 3), POLYGON((0 0, 3 0, 3 3,0 3, 0 0),(1 1, 2 1, 2 2, 1 2, + SRID=4326;GEOMETRYCOLLECTION(POINT(4 0), LINESTRING(4 2, 5 3), POLYGON((0 0, 3 0, 3 3,0 3, 0 0),(1 1, 2 1, 2 2, 1 2, 1 1))) - 4326 33 GEOMETRYCOLLECTION - GEOMETRYCOLLECTION( MULTIPOINT(21 2, 25 5, 30 3), MULTIPOLYGON( ((10 20, 30 40, 44 50, 10 20)), ((105 100, + SRID=4326;GEOMETRYCOLLECTION( MULTIPOINT(21 2, 25 5, 30 3), MULTIPOLYGON( ((10 20, 30 40, 44 50, 10 20)), ((105 100, 120 140, 130 134, 105 100)) ), MULTILINESTRING((10.0 5.0, 20.0 15.0),( 25.0 30.0, 30.0 20.0))) - 4326 34 GEOMETRYCOLLECTION - GEOMETRYCOLLECTION(POINT(4 0), POINT EMPTY, LINESTRING(4 2, 5 3)) - 4326 + SRID=4326;GEOMETRYCOLLECTION(POINT(4 0), POINT EMPTY, LINESTRING(4 2, 5 3)) 35 GEOMETRYCOLLECTION - GEOMETRYCOLLECTION(POINT(4 0), LINESTRING EMPTY, LINESTRING(4 2, 5 3)) - 4326 + SRID=4326;GEOMETRYCOLLECTION(POINT(4 0), LINESTRING EMPTY, LINESTRING(4 2, 5 3)) 36 GEOMETRYCOLLECTION - GEOMETRYCOLLECTION(POINT(4 0), GEOMETRYCOLLECTION EMPTY, LINESTRING(4 2, 5 3)) - 4326 + SRID=4326;GEOMETRYCOLLECTION(POINT(4 0), GEOMETRYCOLLECTION EMPTY, LINESTRING(4 2, 5 3)) 37 GEOMETRYCOLLECTION - GEOMETRYCOLLECTION(POINT(4 0), POLYGON EMPTY, LINESTRING(4 2, 5 3)) - 4326 + SRID=4326;GEOMETRYCOLLECTION(POINT(4 0), POLYGON EMPTY, LINESTRING(4 2, 5 3)) 38 GEOMETRYCOLLECTION - GEOMETRYCOLLECTION(POINT(4 0), MULTILINESTRING EMPTY, LINESTRING(4 2, 5 3)) - 4326 + SRID=4326;GEOMETRYCOLLECTION(POINT(4 0), MULTILINESTRING EMPTY, LINESTRING(4 2, 5 3)) 39 GEOMETRYCOLLECTION - GEOMETRYCOLLECTION(POINT(4 0), MULTIPOINT EMPTY, LINESTRING(4 2, 5 3)) - 4326 + SRID=4326;GEOMETRYCOLLECTION(POINT(4 0), MULTIPOINT EMPTY, LINESTRING(4 2, 5 3)) 40 GEOMETRYCOLLECTION - GEOMETRYCOLLECTION(POINT(4 0), MULTIPOLYGON EMPTY, LINESTRING(4 2, 5 3)) - 4326 + SRID=4326;GEOMETRYCOLLECTION(POINT(4 0), MULTIPOLYGON EMPTY, LINESTRING(4 2, 5 3)) 50 POINT POINT EMPTY - 0 51 LINESTRING LINESTRING EMPTY - 0 52 POLYGON POLYGON EMPTY - 0 53 MULTIPOINT MULTIPOINT EMPTY - 0 54 MULTILINESTRING MULTILINESTRING EMPTY - 0 55 MULTIPOLYGON MULTIPOLYGON EMPTY - 0 56 GEOMETRYCOLLECTION GEOMETRYCOLLECTION EMPTY - 0