]> granicus.if.org Git - postgis/commitdiff
Added beta support for JTS classes
authorMarkus Schaber <markus@schabi.de>
Fri, 18 Feb 2005 14:40:08 +0000 (14:40 +0000)
committerMarkus Schaber <markus@schabi.de>
Fri, 18 Feb 2005 14:40:08 +0000 (14:40 +0000)
git-svn-id: http://svn.osgeo.org/postgis/trunk@1409 b70326c6-7e19-0410-871a-916f4a2858ee

CHANGES
jdbc2/.cvsignore
jdbc2/Makefile
jdbc2/README
jdbc2/jtssrc/examples/JtsTestParser.java [new file with mode: 0644]
jdbc2/jtssrc/org/postgis/jts/JtsBinaryParser.java [new file with mode: 0644]
jdbc2/jtssrc/org/postgis/jts/JtsGeometry.java [new file with mode: 0644]
jdbc2/jtssrc/org/postgis/jts/JtsGisWrapper.java [new file with mode: 0644]
jdbc2/jtssrc/org/postgis/jts/JtsWrapper.java [new file with mode: 0644]

diff --git a/CHANGES b/CHANGES
index ef9bc9a12ba99e3e156803844120738c949a4fe7..31ea9de774fdd589b3b8682fb03b9eca501efc6b 100644 (file)
--- 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
index b02641c40571cc762c5d6a32dee7a1c644211f2c..8559b77ae52ba045ab93e6416f64bbe215d17650 100644 (file)
@@ -4,3 +4,4 @@ postgis.jar
 postgis_debug.jar
 stubbin
 stubcompile
+jtscompile
index 97171652357407bc4af481d7d571fc8aa754427f..d907f8f72a35717e704f68390971f4c7730caf5c 100644 (file)
@@ -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
index ecfd7c03077d08fbf251466e57f17cf0bcdb0a5c..2db0ffa075bc5726fe6a869f9b5f7cfc1da0eab6 100644 (file)
@@ -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 (file)
index 0000000..1b5b2f3
--- /dev/null
@@ -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 (file)
index 0000000..73f903e
--- /dev/null
@@ -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 (file)
index 0000000..de323c5
--- /dev/null
@@ -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 (file)
index 0000000..8050c05
--- /dev/null
@@ -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 (file)
index 0000000..a0796fc
--- /dev/null
@@ -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:
+ * 
+ * &lt;driver-class&gt;com.logitrack.gis.util.PostGisWrapper&lt;/driver-class&gt;
+ * 
+ * @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