From 452842f1785c87d1cf79f6ba8bc7e709601863e0 Mon Sep 17 00:00:00 2001 From: Markus Schaber Date: Fri, 18 Feb 2005 14:40:08 +0000 Subject: [PATCH] Added beta support for JTS classes git-svn-id: http://svn.osgeo.org/postgis/trunk@1409 b70326c6-7e19-0410-871a-916f4a2858ee --- CHANGES | 1 + jdbc2/.cvsignore | 1 + jdbc2/Makefile | 42 ++- jdbc2/README | 7 + jdbc2/jtssrc/examples/JtsTestParser.java | 222 ++++++++++++++++ .../org/postgis/jts/JtsBinaryParser.java | 248 ++++++++++++++++++ jdbc2/jtssrc/org/postgis/jts/JtsGeometry.java | 112 ++++++++ .../jtssrc/org/postgis/jts/JtsGisWrapper.java | 155 +++++++++++ jdbc2/jtssrc/org/postgis/jts/JtsWrapper.java | 161 ++++++++++++ 9 files changed, 947 insertions(+), 2 deletions(-) create mode 100644 jdbc2/jtssrc/examples/JtsTestParser.java create mode 100644 jdbc2/jtssrc/org/postgis/jts/JtsBinaryParser.java create mode 100644 jdbc2/jtssrc/org/postgis/jts/JtsGeometry.java create mode 100644 jdbc2/jtssrc/org/postgis/jts/JtsGisWrapper.java create mode 100644 jdbc2/jtssrc/org/postgis/jts/JtsWrapper.java diff --git a/CHANGES b/CHANGES index ef9bc9a12..31ea9de77 100644 --- a/CHANGES +++ b/CHANGES @@ -22,6 +22,7 @@ PostGIS 1.0.0? failures on simple (single) geometry types. - jdbc2: slightly updated makefile - plugged a leak in GEOS2POSTGIS converter + - jdbc2: added BETA support for jts geometry classes PostGIS 1.0.0RC2 2005/01/26 diff --git a/jdbc2/.cvsignore b/jdbc2/.cvsignore index b02641c40..8559b77ae 100644 --- a/jdbc2/.cvsignore +++ b/jdbc2/.cvsignore @@ -4,3 +4,4 @@ postgis.jar postgis_debug.jar stubbin stubcompile +jtscompile diff --git a/jdbc2/Makefile b/jdbc2/Makefile index 971716523..d907f8f72 100644 --- a/jdbc2/Makefile +++ b/jdbc2/Makefile @@ -84,7 +84,16 @@ SRC= $(SRCDIR)/examples/Test.java \ STUBDIR=stubs STUBBUILD=stubbin/ STUBSRC= $(STUBDIR)/org/postgresql/Connection.java \ - $(STUBDIR)/org/postgresql/PGConnection.java + $(STUBDIR)/org/postgresql/PGConnection.java + +JTSDIR=jtssrc +JTSBUILD=jtsbin/ +JTSSRC= $(JTSDIR)/examples/JtsTestParser.java \ + $(JTSDIR)/org/postgis/jts/JtsBinaryParser.java \ + $(JTSDIR)/org/postgis/jts/JtsGeometry.java \ + $(JTSDIR)/org/postgis/jts/JtsGisWrapper.java \ + $(JTSDIR)/org/postgis/jts/JtsWrapper.java \ + # Now the makefile targets that do the work: @@ -146,7 +155,8 @@ onlinetests: boxtest ptest jtest autoregistertest alltests: onlinetests test clean: - $(DELETE) $(BUILD) bin stubbin postgis.jar postgis_debug.jar compile stubcompile + $(DELETE) $(BUILD) bin stubbin postgis.jar postgis_debug.jar \ + compile stubcompile jtscompile $(JTSBUILD) postgis_jts.jar # The following two targets are needed for debian build, but may be hepful # for someone else, too. @@ -160,3 +170,31 @@ installdirs: @echo Testing for successful inclusion of $(top_makefile) test $(DESTDIR) $(mkinstalldirs) $(DESTDIR) + +# Preliminary JTS support + +postgis_jts: postgis_jts.jar jtstestoffline + @echo "Warning! This is beta code. Use at your own risk." + +$(JTSBUILD): + $(MKDIR) $(JTSBUILD) + + +jtscompile: compile stubcompile $(JTSBUILD) $(JTSSRC) + $(JAVAC) -classpath "$(BUILD):$(CP)" -d $(JTSBUILD) $(JTSSRC) + touch jtscompile + +jtstestoffline: jtscompile + $(JAVA) -classpath "$(JTSBUILD):$(BUILD):$(CP)" $(EXAMPLES)/JtsTestParser offline + +jtstest: jtscompile + $(JAVA) -classpath "$(JTSBUILD):$(BUILD):$(CP)" $(EXAMPLES)/JtsTestParser jdbc:postgres_jts://$(PGHOST):$(PGPORT)/$(PGDATABASE) $(PGUSER) $(PGPASS) + +postgis_jts.jar: jtscompile $(SRCDIR)/org/postgresql/driverconfig.properties + $(JAR) -cf postgis_jts.jar -C $(BUILD) . \ + -C $(SRCDIR) org/postgresql/driverconfig.properties \ + README COPYING_LGPL -C .. COPYING + $(JAR) -uf postgis_jts.jar -C $(JTSBUILD) . + + + \ No newline at end of file diff --git a/jdbc2/README b/jdbc2/README index ecfd7c030..2db0ffa07 100644 --- a/jdbc2/README +++ b/jdbc2/README @@ -193,6 +193,13 @@ PostGIS server to connect to. the PostGIS developer list. +* What about the JTS stuff * + +There's beta support for the JTS 1.6 geometry implementations instead of the +native PostGIS classes on the java client side. Simply add jts_1.6.jar to your +CLASSPATH, "make postgis_jts" and use at your own risk. + + * Phew. That's all? * Yes. For now, at least. diff --git a/jdbc2/jtssrc/examples/JtsTestParser.java b/jdbc2/jtssrc/examples/JtsTestParser.java new file mode 100644 index 000000000..1b5b2f373 --- /dev/null +++ b/jdbc2/jtssrc/examples/JtsTestParser.java @@ -0,0 +1,222 @@ +/* + * Test.java + * + * PostGIS extension for PostgreSQL JDBC driver - example and test classes + * + * (C) 2004 Paul Ramsey, pramsey@refractions.net + * + * (C) 2005 Markus Schaber, schabios@logi-track.com + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License. + * + * This program 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 General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place, Suite 330, Boston, MA 02111-1307 USA or visit the web at + * http://www.gnu.org. + * + * $Id$ + */ + +package examples; + +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.io.WKTReader; + +import org.postgis.jts.JtsGeometry; +import org.postgresql.util.PGtokenizer; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +public class JtsTestParser { + final static WKTReader reader = new WKTReader(); + + /** + * Our set of geometries to test. + */ + public static final String[] testset = new String[]{ + "POINT(10 10 20)", + "MULTIPOINT(10 10 10, 20 20 20)", + "LINESTRING(10 10 20,20 20 20, 50 50 50, 34 34 34)", + "POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))", + "MULTIPOLYGON(((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))", + "MULTILINESTRING((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))", + "GEOMETRYCOLLECTION(POINT(10 10 20),POINT(20 20 20))", + "GEOMETRYCOLLECTION(LINESTRING(10 10 20,20 20 20, 50 50 50, 34 34 34),LINESTRING(10 10 20,20 20 20, 50 50 50, 34 34 34))", + "GEOMETRYCOLLECTION(POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))", + "GEOMETRYCOLLECTION(MULTIPOINT(10 10 10, 20 20 20),MULTIPOINT(10 10 10, 20 20 20))", + "GEOMETRYCOLLECTION(MULTILINESTRING((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))", + "GEOMETRYCOLLECTION(MULTIPOLYGON(((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))),MULTIPOLYGON(((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))))", + "GEOMETRYCOLLECTION(POINT(10 10 20),LINESTRING(10 10 20,20 20 20, 50 50 50, 34 34 34),POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))", + "GEOMETRYCOLLECTION(POINT(10 10 20),MULTIPOINT(10 10 10, 20 20 20),LINESTRING(10 10 20,20 20 20, 50 50 50, 34 34 34),POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),MULTIPOLYGON(((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))),MULTILINESTRING((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))", + "GEOMETRYCOLLECTION EMPTY", // new (correct) representation + "POINT EMPTY", // new (correct) representation + "LINESTRING EMPTY", // new (correct) representation + "POLYGON EMPTY", // new (correct) representation + "MULTIPOINT EMPTY", // new (correct) representation + "MULTILINESTRING EMPTY", // new (correct) representation + "MULTIPOLYGON EMPTY", // new (correct) representation + }; + + /** The srid we use for the srid tests */ + public static final int SRID = 4326; + + /** The string prefix we get for the srid tests */ + public static final String SRIDPREFIX = "SRID=" + SRID + ";"; + + /** How much tests did fail? */ + public static int failcount = 0; + + /** The actual test method */ + public static void test(String WKT, Connection[] conns) throws SQLException { + System.out.println("Original: " + WKT); + Geometry geom = JtsGeometry.geomFromString(WKT); + String parsed = geom.toString(); + System.out.println("Parsed: " + parsed); + Geometry regeom = JtsGeometry.geomFromString(parsed); + String reparsed = regeom.toString(); + System.out.println("Re-Parsed: " + reparsed); + if (safeGeomUnequal(geom, regeom)) { + System.out.println("--- Geometries are not equal!"); + failcount++; + } else if (!reparsed.equals(parsed)) { + System.out.println("--- Text Reps are not equal!"); + failcount++; + } else { + System.out.println("Equals: yes"); + } + for (int i = 0; i < conns.length; i++) { + System.out.println("Testing on connection " + i + ": " + conns[i].getCatalog()); + Statement statement = conns[i].createStatement(); + + try { + Geometry sqlGeom = viaSQL(WKT, statement); + System.out.println("SQLin : " + sqlGeom.toString()); + if (safeGeomUnequal(geom, sqlGeom)) { + System.out.println("--- Geometries after SQL are not equal!"); + failcount++; + } else { + System.out.println("Eq SQL in: yes"); + } + } catch (SQLException e) { + System.out.println("--- Server side error: " + e.toString()); + failcount++; + } + + try { + Geometry sqlreGeom = viaSQL(parsed, statement); + System.out.println("SQLout : " + sqlreGeom.toString()); + if (safeGeomUnequal(geom, sqlreGeom)) { + System.out.println("--- reparsed Geometries after SQL are not equal!"); + failcount++; + } else { + System.out.println("Eq SQLout: yes"); + } + } catch (SQLException e) { + System.out.println("--- Server side error: " + e.toString()); + failcount++; + } + + statement.close(); + } + System.out.println("***"); + } + + private static boolean safeGeomUnequal(Geometry geom, Geometry regeom) { + try { + return !geom.equals(regeom); + } catch (java.lang.IllegalArgumentException e) { + System.out.println(".equals call failed: " + e.getMessage()); + return false; + } + } + + /** Pass a geometry representation through the SQL server */ + private static Geometry viaSQL(String rep, Statement stat) throws SQLException { + ResultSet rs = stat.executeQuery("SELECT geometry_in('" + rep + "')"); + rs.next(); + return ((JtsGeometry) rs.getObject(1)).getGeometry(); + } + + /** + * Connect to the databases + * + * We use DriverWrapper here. For alternatives, see the DriverWrapper + * Javadoc + * + * @param dbuser + * + * @throws ClassNotFoundException + * + * @see org.postgis.DriverWrapper + * + */ + public static Connection connect(String url, String dbuser, String dbpass) throws SQLException, + ClassNotFoundException { + Connection conn; + Class.forName("org.postgis.jts.JtsWrapper"); + conn = DriverManager.getConnection(url, dbuser, dbpass); + return conn; + } + + /** Our apps entry point */ + public static void main(String[] args) throws SQLException, ClassNotFoundException { + PGtokenizer dburls; + String dbuser = null; + String dbpass = null; + + if (args.length == 1 && args[0].equalsIgnoreCase("offline")) { + System.out.println("Performing only offline tests"); + dburls = new PGtokenizer("", ';'); + } else if (args.length == 3) { + System.out.println("Performing offline and online tests"); + dburls = new PGtokenizer(args[0], ';'); + + dbuser = args[1]; + dbpass = args[2]; + } else { + System.err.println("Usage: java examples/JtsTestParser dburls user pass [tablename]"); + System.err.println(" or: java examples/JtsTestParser offline"); + System.err.println(); + System.err.println("dburls has one or more jdbc urls separated by ; in the following format"); + System.err.println("jdbc:postgresql://HOST:PORT/DATABASENAME"); + System.err.println("tablename is 'jdbc_test' by default."); + System.exit(1); + // Signal the compiler that code flow ends here. + return; + } + + Connection[] conns; + conns = new Connection[dburls.getSize()]; + for (int i = 0; i < dburls.getSize(); i++) { + System.out.println("Creating JDBC connection to " + dburls.getToken(i)); + conns[i] = connect(dburls.getToken(i), dbuser, dbpass); + } + + System.out.println("Performing tests..."); + System.out.println("***"); + + for (int i = 0; i < testset.length; i++) { + test(testset[i], conns); + test(SRIDPREFIX + testset[i], conns); + } + + System.out.print("cleaning up..."); + for (int i = 0; i < conns.length; i++) { + conns[i].close(); + } + + //System.out.println("Finished."); + System.out.println("Finished, " + failcount + " tests failed!"); + } +} \ No newline at end of file diff --git a/jdbc2/jtssrc/org/postgis/jts/JtsBinaryParser.java b/jdbc2/jtssrc/org/postgis/jts/JtsBinaryParser.java new file mode 100644 index 000000000..73f903e4e --- /dev/null +++ b/jdbc2/jtssrc/org/postgis/jts/JtsBinaryParser.java @@ -0,0 +1,248 @@ +/* + * JtsBinaryParser.java + * + * Binary Parser for JTS - relies on org.postgis V1.0.0+ package. + * + * (C) 2005 Markus Schaber, schabios@logi-track.com + * + * 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. + * + * 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 or visit the web at + * http://www.gnu.org. + * + * $Id$ + */ +package org.postgis.jts; + +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.CoordinateSequence; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryCollection; +import com.vividsolutions.jts.geom.GeometryFactory; +import com.vividsolutions.jts.geom.LineString; +import com.vividsolutions.jts.geom.LinearRing; +import com.vividsolutions.jts.geom.MultiLineString; +import com.vividsolutions.jts.geom.MultiPoint; +import com.vividsolutions.jts.geom.MultiPolygon; +import com.vividsolutions.jts.geom.Point; +import com.vividsolutions.jts.geom.Polygon; +import com.vividsolutions.jts.geom.impl.PackedCoordinateSequence; + +import org.postgis.binary.ByteGetter; +import org.postgis.binary.ValueGetter; +import org.postgis.binary.ByteGetter.BinaryByteGetter; +import org.postgis.binary.ByteGetter.StringByteGetter; + +/** + * Parse binary representation of geometries. Currently, only text rep (hexed) + * implementation is tested. + * + * It should be easy to add char[] and CharSequence ByteGetter instances, + * although the latter one is not compatible with older jdks. + * + * I did not implement real unsigned 32-bit integers or emulate them with long, + * as both java Arrays and Strings currently can have only 2^31-1 elements + * (bytes), so we cannot even get or build Geometries with more than approx. + * 2^28 coordinates (8 bytes each). + * + * @author markus.schaber@logi-track.com + * + */ +public class JtsBinaryParser { + final static GeometryFactory geofac = new GeometryFactory(); + + /** + * Get the appropriate ValueGetter for my endianness + * + * @param bytes The appropriate Byte Getter + * + * @return the ValueGetter + */ + public static ValueGetter valueGetterForEndian(ByteGetter bytes) { + if (bytes.get(0) == ValueGetter.XDR.NUMBER) { // XDR + return new ValueGetter.XDR(bytes); + } else if (bytes.get(0) == ValueGetter.NDR.NUMBER) { + return new ValueGetter.NDR(bytes); + } else { + throw new IllegalArgumentException("Unknown Endian type:" + bytes.get(0)); + } + } + + /** + * Parse a hex encoded geometry + * + * Is synchronized to protect offset counter. (Unfortunately, Java does not + * have neither call by reference nor multiple return values.) + */ + public synchronized Geometry parse(String value) { + StringByteGetter bytes = new ByteGetter.StringByteGetter(value); + return parseGeometry(valueGetterForEndian(bytes)); + } + + /** + * Parse a binary encoded geometry. + * + * Is synchronized to protect offset counter. (Unfortunately, Java does not + * have neither call by reference nor multiple return values.) + */ + public synchronized Geometry parse(byte[] value) { + BinaryByteGetter bytes = new ByteGetter.BinaryByteGetter(value); + return parseGeometry(valueGetterForEndian(bytes)); + } + + /** Parse a geometry starting at offset. */ + protected Geometry parseGeometry(ValueGetter data) { + byte endian = data.getByte(); //skip and test endian flag + if (endian != data.endian) { + throw new IllegalArgumentException("Endian inconsistency!"); + } + int typeword = data.getInt(); + + int realtype = typeword & 0x1FFFFFFF; //cut off high flag bits + + boolean haveZ = (typeword & 0x80000000) != 0; + boolean haveM = (typeword & 0x40000000) != 0; + boolean haveS = (typeword & 0x20000000) != 0; + + int srid = -1; + + if (haveS) { + srid = data.getInt(); + } + Geometry result1; + switch (realtype) { + case org.postgis.Geometry.POINT : + result1 = parsePoint(data, haveZ, haveM); + break; + case org.postgis.Geometry.LINESTRING : + result1 = parseLineString(data, haveZ, haveM); + break; + case org.postgis.Geometry.POLYGON : + result1 = parsePolygon(data, haveZ, haveM); + break; + case org.postgis.Geometry.MULTIPOINT : + result1 = parseMultiPoint(data); + break; + case org.postgis.Geometry.MULTILINESTRING : + result1 = parseMultiLineString(data); + break; + case org.postgis.Geometry.MULTIPOLYGON : + result1 = parseMultiPolygon(data); + break; + case org.postgis.Geometry.GEOMETRYCOLLECTION : + result1 = parseCollection(data); + break; + default : + throw new IllegalArgumentException("Unknown Geometry Type!"); + } + + Geometry result = result1; + + if (haveS) { + result.setSRID(srid); + } + return result; + } + + private Point parsePoint(ValueGetter data, boolean haveZ, boolean haveM) { + double X = data.getDouble(); + double Y = data.getDouble(); + Point result; + if (haveZ) { + double Z = data.getDouble(); + result = geofac.createPoint(new Coordinate(X, Y, Z)); + } else { + result = geofac.createPoint(new Coordinate(X, Y)); + } + + if (haveM) { //skip M value + data.getDouble(); + } + + return result; + } + + /** Parse an Array of "full" Geometries */ + private void parseGeometryArray(ValueGetter data, Geometry[] container) { + for (int i = 0; i < container.length; i++) { + container[i] = parseGeometry(data); + } + } + + /** + * Parse an Array of "slim" Points (without endianness and type, part of + * LinearRing and Linestring, but not MultiPoint! + * + * @param haveZ + * @param haveM + */ + private CoordinateSequence parseCS(ValueGetter data, boolean haveZ, boolean haveM) { + int count = data.getInt(); + int dims = haveZ ? 3 : 2; + CoordinateSequence cs = new PackedCoordinateSequence.Double(count, dims); + + for (int i = 0; i < count; i++) { + for (int d = 0; d < dims; d++) { + cs.setOrdinate(i, d, data.getDouble()); + } + if (haveM) { //skip M value + data.getDouble(); + } + } + return cs; + } + + private MultiPoint parseMultiPoint(ValueGetter data) { + Point[] points = new Point[data.getInt()]; + parseGeometryArray(data, points); + return geofac.createMultiPoint(points); + } + + private LineString parseLineString(ValueGetter data, boolean haveZ, boolean haveM) { + return geofac.createLineString(parseCS(data, haveZ, haveM)); + } + + private LinearRing parseLinearRing(ValueGetter data, boolean haveZ, boolean haveM) { + return geofac.createLinearRing(parseCS(data, haveZ, haveM)); + } + + private Polygon parsePolygon(ValueGetter data, boolean haveZ, boolean haveM) { + int holecount = data.getInt()-1; + LinearRing[] rings = new LinearRing[holecount]; + LinearRing shell = parseLinearRing(data, haveZ, haveM); + for (int i = 0; i < holecount; i++) { + rings[i] = parseLinearRing(data, haveZ, haveM); + } + return geofac.createPolygon(shell, rings); + } + + private MultiLineString parseMultiLineString(ValueGetter data) { + int count = data.getInt(); + LineString[] strings = new LineString[count]; + parseGeometryArray(data, strings); + return geofac.createMultiLineString(strings); + } + + private MultiPolygon parseMultiPolygon(ValueGetter data) { + int count = data.getInt(); + Polygon[] polys = new Polygon[count]; + parseGeometryArray(data, polys); + return geofac.createMultiPolygon(polys); + } + + private GeometryCollection parseCollection(ValueGetter data) { + int count = data.getInt(); + Geometry[] geoms = new Geometry[count]; + parseGeometryArray(data, geoms); + return geofac.createGeometryCollection(geoms); + } +} \ No newline at end of file diff --git a/jdbc2/jtssrc/org/postgis/jts/JtsGeometry.java b/jdbc2/jtssrc/org/postgis/jts/JtsGeometry.java new file mode 100644 index 000000000..de323c5d4 --- /dev/null +++ b/jdbc2/jtssrc/org/postgis/jts/JtsGeometry.java @@ -0,0 +1,112 @@ +/* + * JtsGeometry.java + * + * Wrapper for PostgreSQL JDBC driver to allow transparent reading and writing + * of JTS geometries + * + * (C) 2005 Markus Schaber, schabios@logi-track.com + * + * 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. + * + * 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 or visit the web at + * http://www.gnu.org. + * + * $Id$ + */ + +package org.postgis.jts; + +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.io.WKTReader; + +import org.postgresql.util.PGobject; + +import java.sql.SQLException; + +/** + * JTS Geometry SQL wrapper + * + * @author Markus Schaber + */ + +public class JtsGeometry extends PGobject { + + Geometry geom; + + final static WKTReader reader = new WKTReader(); + final static JtsBinaryParser bp = new JtsBinaryParser(); + + + public JtsGeometry() { + //Constructor called by JDBC drivers + } + + public JtsGeometry(Geometry geom) { + this.geom = geom; + } + + public JtsGeometry(String value) throws SQLException { + setValue(value); + } + + public void setValue(String value) throws SQLException { + geom = geomFromString(value); + } + + public static Geometry geomFromString(String value) throws SQLException { + try { + value = value.trim(); + if (value.startsWith("00") || value.startsWith("01")) { + return bp.parse(value); + } else { + Geometry result; + int srid = -1; + //break up geometry into srid and wkt + if (value.startsWith("SRID=")) { + String[] temp = value.split(";"); + value = temp[1].trim(); + srid = Integer.parseInt(temp[0].substring(5)); + } + result = reader.read(value); + result.setSRID(srid); + return result; + } + } catch (Exception E) { + E.printStackTrace(); + throw new SQLException("Error parsing SQL data:" + E); + } + } + + public Geometry getGeometry() { + return geom; + } + + public String toString() { + return geom.toString(); + } + + public String getValue() { + return geom.toString(); + } + + public Object clone() { + JtsGeometry obj = new JtsGeometry(geom); + obj.setType(type); + return obj; + } + + public boolean equals(Object obj) { + if (obj instanceof JtsGeometry) + return ((JtsGeometry) obj).getValue().equals(geom); + return false; + } +} \ No newline at end of file diff --git a/jdbc2/jtssrc/org/postgis/jts/JtsGisWrapper.java b/jdbc2/jtssrc/org/postgis/jts/JtsGisWrapper.java new file mode 100644 index 000000000..8050c050d --- /dev/null +++ b/jdbc2/jtssrc/org/postgis/jts/JtsGisWrapper.java @@ -0,0 +1,155 @@ +/* + * JtsWrapper.java + * + * Allows transparent usage of JTS Geometry classes via PostgreSQL JDBC driver + * connected to a PostGIS enabled PostgreSQL server. + * + * (C) 2005 Markus Schaber, schabios@logi-track.com + * + * 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. + * + * 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 or visit the web at + * http://www.gnu.org. + * + * $Id$ + */ + +package org.postgis.jts; + +import org.postgresql.Driver; +import org.postgresql.PGConnection; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.Properties; + +/** + * JtsGisWrapper + * + * Wraps the PostGreSQL Driver to add the JTS/PostGIS Object Classes. + * + * This method currently works with J2EE DataSource implementations, and with + * DriverManager framework. + * + * Simply replace the "jdbc:postgresql:" with a "jdbc:postgresql_postGIS" in the + * jdbc URL. + * + * @author schabi + * + */ +public class JtsGisWrapper extends Driver { + + private static final String POSTGRES_PROTOCOL = "jdbc:postgresql:"; + private static final String POSTGIS_PROTOCOL = "jdbc:postgresql_JTS:"; + public static final String REVISION = "$Revision$"; + + public JtsGisWrapper() { + super(); + } + + static { + try { + // Analogy to org.postgresql.Driver + java.sql.DriverManager.registerDriver(new JtsGisWrapper()); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + /** + * Creates a postgresql connection, and then adds the PostGIS data types to + * it calling addpgtypes() + * + * @param url the URL of the database to connect to + * @param info a list of arbitrary tag/value pairs as connection arguments + * @return a connection to the URL or null if it isnt us + * @exception SQLException if a database access error occurs + * + * @see java.sql.Driver#connect + * @see org.postgresql.Driver + */ + public java.sql.Connection connect(String url, Properties info) throws SQLException { + url = mangleURL(url); + Connection result = super.connect(url, info); + addGISTypes((PGConnection) result); + return result; + } + + /** + * adds the JTS/PostGIS Data types to a PG Connection. + */ + public static void addGISTypes(PGConnection pgconn) { + pgconn.addDataType("geometry", "com.logitrack.gis.util.JtsGeometry"); + pgconn.addDataType("box3d", "org.postgis.PGbox3d"); + //pgconn.addDataType("geometry", + // com.logitrack.gis.util.JtsGeometry.class); + //pgconn.addDataType("box3d", org.postgis.PGbox3d.class); + } + + /** + * Mangles the PostGIS URL to return the original PostGreSQL URL + */ + public static String mangleURL(String url) throws SQLException { + if (url.startsWith(POSTGIS_PROTOCOL)) { + return POSTGRES_PROTOCOL + url.substring(POSTGIS_PROTOCOL.length()); + } else { + throw new SQLException("Unknown protocol or subprotocol in url " + url); + } + } + + /** + * Returns true if the driver thinks it can open a connection to the given + * URL. Typically, drivers will return true if they understand the + * subprotocol specified in the URL and false if they don't. Our protocols + * start with jdbc:postgresql_postGIS: + * + * @see java.sql.Driver#acceptsURL + * @param url the URL of the driver + * @return true if this driver accepts the given URL + * @exception SQLException if a database-access error occurs (Dont know why + * it would *shrug*) + */ + public boolean acceptsURL(String url) throws SQLException { + try { + url = mangleURL(url); + } catch (SQLException e) { + return false; + } + return super.acceptsURL(url); + } + + /** + * Gets the underlying drivers major version number + * + * @return the drivers major version number + */ + + public int getMajorVersion() { + return super.getMajorVersion(); + } + + /** + * Get the underlying drivers minor version number + * + * @return the drivers minor version number + */ + public int getMinorVersion() { + return super.getMinorVersion(); + } + + /** + * Returns our own CVS version plus postgres Version + */ + public static String getVersion() { + return "JtsGisWrapper " + REVISION + ", wrapping " + Driver.getVersion(); + } +} \ No newline at end of file diff --git a/jdbc2/jtssrc/org/postgis/jts/JtsWrapper.java b/jdbc2/jtssrc/org/postgis/jts/JtsWrapper.java new file mode 100644 index 000000000..a0796fc16 --- /dev/null +++ b/jdbc2/jtssrc/org/postgis/jts/JtsWrapper.java @@ -0,0 +1,161 @@ +/* + * JtsWrapper.java + * + * Allows transparent usage of JTS Geometry classes via PostgreSQL JDBC driver + * connected to a PostGIS enabled PostgreSQL server. + * + * (C) 2005 Markus Schaber, schabios@logi-track.com + * + * 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. + * + * 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 or visit the web at + * http://www.gnu.org. + * + * $Id$ + */ + +package org.postgis.jts; + +import org.postgresql.Driver; +import org.postgresql.PGConnection; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.Properties; + +/** + * DriverWrapper + * + * Wraps the PostGreSQL Driver to add the JTS/PostGIS Object Classes. + * + * This method currently works with J2EE DataSource implementations, and with + * DriverManager framework. + * + * Simply replace the "jdbc:postgresql:" with a "jdbc:postgres_jts:" in the jdbc + * URL. + * + * When using the drivermanager, you need to initialize JtsWrapper instead of + * (or in addition to) org.postgresql.Driver. When using a J2EE DataSource + * implementation, set the driver class property in the datasource config, the + * following works for jboss: + * + * <driver-class>com.logitrack.gis.util.PostGisWrapper</driver-class> + * + * @author schabi + * + */ +public class JtsWrapper extends Driver { + + private static final String POSTGRES_PROTOCOL = "jdbc:postgresql:"; + private static final String POSTGIS_PROTOCOL = "jdbc:postgres_jts:"; + public static final String REVISION = "$Revision$"; + + public JtsWrapper() { + super(); + } + + static { + try { + // Try to register ourself to the DriverManager + java.sql.DriverManager.registerDriver(new JtsWrapper()); + } catch (SQLException e) { + Driver.info("Error registering PostgreSQL Jts Wrapper Driver", e); + } + } + + /** + * Creates a postgresql connection, and then adds the JTS GIS data types to + * it calling addpgtypes() + * + * @param url the URL of the database to connect to + * @param info a list of arbitrary tag/value pairs as connection arguments + * @return a connection to the URL or null if it isnt us + * @exception SQLException if a database access error occurs + * + * @see java.sql.Driver#connect + * @see org.postgresql.Driver + */ + public java.sql.Connection connect(String url, Properties info) throws SQLException { + url = mangleURL(url); + Connection result = super.connect(url, info); + addGISTypes((PGConnection) result); + return result; + } + + /** + * adds the JTS/PostGIS Data types to a PG Connection. + */ + public static void addGISTypes(PGConnection pgconn) { + // Add data type up to PostgreSQL jdbc driver V7.4 + pgconn.addDataType("geometry", "org.postgis.jts.JtsGeometry"); + + // Use the following for PostgreSQL jdbc driver V8.0 or newer + // The above way still works, but is deprecated. + // pgconn.addDataType("geometry", + // com.logitrack.gis.util.JtsGeometry.class); + } + + /** + * Mangles the PostGIS URL to return the original PostGreSQL URL + */ + public static String mangleURL(String url) throws SQLException { + if (url.startsWith(POSTGIS_PROTOCOL)) { + return POSTGRES_PROTOCOL + url.substring(POSTGIS_PROTOCOL.length()); + } else { + throw new SQLException("Unknown protocol or subprotocol in url " + url); + } + } + + /** + * Check whether the driver thinks he can handle the given URL. + * + * @see java.sql.Driver#acceptsURL + * @param url the URL of the driver + * @return true if this driver accepts the given URL + * @exception SQLException Passed through from the underlying PostgreSQL + * driver, should not happen. + */ + public boolean acceptsURL(String url) throws SQLException { + try { + url = mangleURL(url); + } catch (SQLException e) { + return false; + } + return super.acceptsURL(url); + } + + /** + * Gets the underlying drivers major version number + * + * @return the drivers major version number + */ + + public int getMajorVersion() { + return super.getMajorVersion(); + } + + /** + * Get the underlying drivers minor version number + * + * @return the drivers minor version number + */ + public int getMinorVersion() { + return super.getMinorVersion(); + } + + /** + * Returns our own CVS version plus postgres Version + */ + public static String getVersion() { + return "JtsGisWrapper " + REVISION + ", wrapping " + Driver.getVersion(); + } +} \ No newline at end of file -- 2.49.0