From: Sandro Santilli Date: Sun, 30 Jan 2005 09:46:46 +0000 (+0000) Subject: Added BOX2D and BOX3D support and tests, by Markus Shaber. X-Git-Tag: pgis_1_0_0RC3~85 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=07a1e625ba14fd1304f207c178ce8a1a96fd765e;p=postgis Added BOX2D and BOX3D support and tests, by Markus Shaber. git-svn-id: http://svn.osgeo.org/postgis/trunk@1354 b70326c6-7e19-0410-871a-916f4a2858ee --- diff --git a/jdbc2/Makefile b/jdbc2/Makefile index 4bc218cc2..bc079b591 100644 --- a/jdbc2/Makefile +++ b/jdbc2/Makefile @@ -23,6 +23,7 @@ PGUSER?=psql PGPASS?=guess SRC= $(SRCDIR)/examples/Test.java \ + $(SRCDIR)/examples/TestBoxes.java \ $(SRCDIR)/examples/TestParser.java \ $(SRCDIR)/examples/TestServer.java \ $(SRCDIR)/org/postgis/ComposedGeom.java \ @@ -34,8 +35,8 @@ SRC= $(SRCDIR)/examples/Test.java \ $(SRCDIR)/org/postgis/MultiLineString.java \ $(SRCDIR)/org/postgis/MultiPoint.java \ $(SRCDIR)/org/postgis/MultiPolygon.java \ + $(SRCDIR)/org/postgis/PGbox2d.java \ $(SRCDIR)/org/postgis/PGbox3d.java \ - $(SRCDIR)/org/postgis/PGbox.java \ $(SRCDIR)/org/postgis/PGgeometry.java \ $(SRCDIR)/org/postgis/PointComposedGeom.java \ $(SRCDIR)/org/postgis/Point.java \ @@ -43,7 +44,7 @@ SRC= $(SRCDIR)/examples/Test.java \ all: jar \ - test + offlinetests jar: compile $(JAR) -cf postgis.jar -C $(BUILD) . -C $(SRCDIR) org/postgresql/postgresql.properties README @@ -70,6 +71,20 @@ ptestoffline: compile ptest: compile $(JAVA) -classpath "$(BUILD):$(CP)" $(EXAMPLES)/TestParser jdbc:postgresql_postGIS://$(PGHOST):$(PGPORT)/$(PGDATABASE) $(PGUSER) $(PGPASS) +boxtestoffline: compile + $(JAVA) -classpath "$(BUILD):$(CP)" $(EXAMPLES)/TestBoxes offline + +boxtest: compile + $(JAVA) -classpath "$(BUILD):$(CP)" $(EXAMPLES)/TestBoxes jdbc:postgresql_postGIS://$(PGHOST):$(PGPORT)/$(PGDATABASE) $(PGUSER) $(PGPASS) + +offlinetests: boxtestoffline ptestoffline test + +onlinetests: boxtest ptest jtest + +# boxtest and ptest include boxtestoffline and ptestoffline, so we only need +# to run test in addition to the onlinetests +alltests: onlinetests test + clean: $(DELETE) $(BUILD) bin postgis.jar postgis_debug.jar compile diff --git a/jdbc2/src/examples/TestBoxes.java b/jdbc2/src/examples/TestBoxes.java new file mode 100644 index 000000000..1f8755764 --- /dev/null +++ b/jdbc2/src/examples/TestBoxes.java @@ -0,0 +1,209 @@ +/* + * Test client and server side Parsing of canonical text representations, as + * well as the PostGisWrapper jdbc extension. + * + * (C) 2005 Markus Schaber, logi-track ag, Zürich, Switzerland + * + * This file is licensed under the GNU GPL. *** put full notice here *** + * + * $Id$ + */ + +package examples; + +import org.postgis.PGbox2d; +import org.postgis.PGbox3d; +import org.postgresql.util.PGobject; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +public class TestBoxes { + + /** Our test candidates: */ + public static final String[] BOXEN3D = new String[]{ + "BOX3D(1 2 3,4 5 6)", //3d variant + "BOX3D(1 2,4 5)"// 2d variant + }; + public static final String[] BOXEN2D = new String[]{"BOX(1 2,3 4)"}; + + /** 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 orig, PGobject candidate, Connection[] conns) + throws SQLException { + + System.out.println("Original: " + orig); + String redone = candidate.toString(); + System.out.println("Parsed: " + redone); + + if (!orig.equals(redone)) { + System.out.println("--- Recreated Text Rep not equal!"); + failcount++; + } + + // Let's simulate the way pgjdbc uses to create PGobjects + PGobject recreated; + try { + recreated = (PGobject) candidate.getClass().newInstance(); + } catch (Exception e) { + System.out.println("--- pgjdbc instantiation failed!"); + System.out.println("--- " + e.getMessage()); + failcount++; + return; + } + recreated.setValue(redone); + + String reparsed = recreated.toString(); + System.out.println("Re-Parsed: " + reparsed); + if (!recreated.equals(candidate)) { + System.out.println("--- Recreated boxen are not equal!"); + failcount++; + } else if (!reparsed.equals(orig)) { + System.out.println("--- 2nd generation 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 { + PGobject sqlGeom = viaSQL(candidate, statement); + System.out.println("SQLin : " + sqlGeom.toString()); + if (!candidate.equals(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 { + PGobject sqlreGeom = viaSQL(recreated, statement); + System.out.println("SQLout : " + sqlreGeom.toString()); + if (!candidate.equals(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("***"); + } + + /** Pass a geometry representation through the SQL server */ + private static PGobject viaSQL(PGobject obj, Statement stat) throws SQLException { + ResultSet rs = stat.executeQuery("SELECT '" + obj.toString() + "'::" + obj.getType()); + rs.next(); + return (PGobject) rs.getObject(1); + } + + /** + * 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.DriverWrapper"); + conn = DriverManager.getConnection(url, dbuser, dbpass); + return conn; + } + + /** Our apps entry point */ + public static void main(String[] args) throws SQLException, ClassNotFoundException { + String[] dburls; + String dbuser = null; + String dbpass = null; + + if (args.length == 1 && args[0].equalsIgnoreCase("offline")) { + System.out.println("Performing only offline tests"); + dburls = new String[0]; + } else if (args.length == 3) { + System.out.println("Performing offline and online tests"); + dburls = args[0].split(";"); + dbuser = args[1]; + dbpass = args[2]; + } else { + System.err.println("Usage: java examples/TestParser dburls user pass [tablename]"); + System.err.println(" or: java examples/TestParser 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. + throw new AssertionError(); + } + + Connection[] conns; + conns = new Connection[dburls.length]; + for (int i = 0; i < dburls.length; i++) { + System.out.println("Creating JDBC connection to " + dburls[i]); + conns[i] = connect(dburls[i], dbuser, dbpass); + } + + System.out.println("Performing tests..."); + System.out.println("***"); + + for (int i = 0; i < BOXEN3D.length; i++) { + try { + PGbox3d candidate = new PGbox3d(BOXEN3D[i]); + test(BOXEN3D[i], candidate, conns); + } catch (SQLException e) { + System.out.println("--- Instantiation of " + BOXEN3D[i] + "failed:"); + System.out.println("--- " + e.getMessage()); + failcount++; + } + } + + for (int i = 0; i < BOXEN2D.length; i++) { + try { + PGbox2d candidate = new PGbox2d(BOXEN2D[i]); + test(BOXEN2D[i], candidate, conns); + } catch (SQLException e) { + System.out.println("--- Instantiation of " + BOXEN2D[i] + "failed:"); + System.out.println("--- " + e.getMessage()); + failcount++; + } + } + + 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/src/org/postgis/DriverWrapper.java b/jdbc2/src/org/postgis/DriverWrapper.java index d50e7212f..56afa1331 100644 --- a/jdbc2/src/org/postgis/DriverWrapper.java +++ b/jdbc2/src/org/postgis/DriverWrapper.java @@ -107,13 +107,15 @@ public class DriverWrapper extends Driver { // This is correct for PostgreSQL jdbc drivers up to V7.4 pgconn.addDataType("geometry", "org.postgis.PGgeometry"); pgconn.addDataType("box3d", "org.postgis.PGbox3d"); - pgconn.addDataType("box3d", "org.postgis.PGbox"); + pgconn.addDataType("box2d", "org.postgis.PGbox2d"); + // If you use PostgreSQL jdbc drivers V8.0 or newer, the above // methods are deprecated (but still work for now), and you // may want to use the two lines below instead. + //pgconn.addDataType("geometry", org.postgis.PGgeometry.class); //pgconn.addDataType("box3d", org.postgis.PGbox3d.class); - //pgconn.addDataType("box3d", org.postgis.PGBox.class); + //pgconn.addDataType("box2d", org.postgis.PGbox2d.class); } /** diff --git a/jdbc2/src/org/postgis/PGbox2d.java b/jdbc2/src/org/postgis/PGbox2d.java new file mode 100644 index 000000000..be3b71494 --- /dev/null +++ b/jdbc2/src/org/postgis/PGbox2d.java @@ -0,0 +1,38 @@ +package org.postgis; + +import java.sql.SQLException; + +public class PGbox2d extends PGboxbase { + + public PGbox2d() { + super(); + } + + public PGbox2d(Point llb, Point urt) { + super(llb, urt); + } + + public PGbox2d(String value) throws SQLException { + super(value); + } + + public void setValue(String value) throws SQLException { + super.setValue(value); + + if (llb.dimension!=2 || urt.dimension!=2) { + throw new SQLException("PGbox2d is only allowed to have 2 dimensions!"); + } + } + + public String getPrefix() { + return "BOX"; + } + + public String getPGtype() { + return "box2d"; + } + + protected PGboxbase newInstance() { + return new PGbox2d(); + } +} diff --git a/jdbc2/src/org/postgis/PGbox3d.java b/jdbc2/src/org/postgis/PGbox3d.java index 8d3d5d2df..70141fd7a 100644 --- a/jdbc2/src/org/postgis/PGbox3d.java +++ b/jdbc2/src/org/postgis/PGbox3d.java @@ -1,72 +1,29 @@ package org.postgis; -import org.postgresql.util.PGobject; -import org.postgresql.util.PGtokenizer; - import java.sql.SQLException; -/* - * Updates Oct 2002 - data members made private - getLLB() and getURT() methods - * added - */ - -public class PGbox3d extends PGobject { - - /** - * The lower left bottom corner of the box. - */ - private Point llb; - - /** - * The upper right top corner of the box. - */ - private Point urt; - +public class PGbox3d extends PGboxbase { public PGbox3d() { - // do nothing. + super(); } public PGbox3d(Point llb, Point urt) { - this.llb = llb; - this.urt = urt; + super(llb, urt); } public PGbox3d(String value) throws SQLException { - setValue(value); - } - - public void setValue(String value) throws SQLException { - value = value.trim(); - if (value.startsWith("BOX3D")) { - value = value.substring(5); - } - PGtokenizer t = new PGtokenizer(PGtokenizer.removePara(value.trim()), ','); - llb = new Point(t.getToken(0)); - urt = new Point(t.getToken(1)); - } - - public String getValue() { - return "BOX3D (" + llb.getValue() + "," + urt.getValue() + ")"; + super(value); } - public String toString() { - return getValue(); + public String getPrefix() { + return ("BOX3D"); } - public Object clone() { - PGbox3d obj = new PGbox3d(llb, urt); - obj.setType(type); - return obj; + public String getPGtype() { + return ("box3d"); } - /** Returns the lower left bottom corner of the box as a Point object */ - public Point getLLB() { - return llb; + protected PGboxbase newInstance() { + return new PGbox3d(); } - - /** Returns the upper right top corner of the box as a Point object */ - public Point getURT() { - return urt; - } - -} \ No newline at end of file +} diff --git a/jdbc2/src/org/postgis/PGboxbase.java b/jdbc2/src/org/postgis/PGboxbase.java new file mode 100644 index 000000000..3b31bf9f6 --- /dev/null +++ b/jdbc2/src/org/postgis/PGboxbase.java @@ -0,0 +1,144 @@ +package org.postgis; + +import org.postgresql.util.PGobject; +import org.postgresql.util.PGtokenizer; + +import java.sql.SQLException; + +/* + * Updates Oct 2002 - data members made private - getLLB() and getURT() methods + * added + */ + +public abstract class PGboxbase extends PGobject { + + /** + * The lower left bottom corner of the box. + */ + protected Point llb; + + /** + * The upper right top corner of the box. + */ + protected Point urt; + + /** + * The Prefix we have in WKT rep. + * + * I use an abstract method here so we do not need to replicate the String + * object in every instance. + * + */ + public abstract String getPrefix(); + + /** + * The Postgres type we have (same construct as getPrefix()) + */ + public abstract String getPGtype(); + + public PGboxbase() { + this.setType(getPGtype()); + } + + public PGboxbase(Point llb, Point urt) { + this(); + this.llb = llb; + this.urt = urt; + } + + public PGboxbase(String value) throws SQLException { + this(); + setValue(value); + } + + public void setValue(String value) throws SQLException { + int srid = -1; + value = value.trim(); + if (value.startsWith("SRID=")) { + String[] temp = value.split(";", 2); + value = temp[1].trim(); + srid = Integer.parseInt(temp[0].substring(5)); + } + if (value.startsWith(getPrefix())) { + value = value.substring(getPrefix().length()); + } + PGtokenizer t = new PGtokenizer(PGtokenizer.removePara(value.trim()), ','); + llb = new Point(t.getToken(0)); + urt = new Point(t.getToken(1)); + if (srid != -1) { + llb.setSrid(srid); + urt.setSrid(srid); + } + } + + public String getValue() { + StringBuffer sb = new StringBuffer(); + outerWKT(sb); + return sb.toString(); + } + + private void outerWKT(StringBuffer sb) { + sb.append(getPrefix()); + sb.append('('); + llb.innerWKT(sb); + sb.append(','); + urt.innerWKT(sb); + sb.append(')'); + } + + /** + * Unlike geometries, toString() does _not_ contain the srid, as server-side + * PostGIS cannot parse this. + */ + public String toString() { + return getValue(); + } + + /** Returns the lower left bottom corner of the box as a Point object */ + public Point getLLB() { + return llb; + } + + /** Returns the upper right top corner of the box as a Point object */ + public Point getURT() { + return urt; + } + + public boolean equals(Object other) { + if (other instanceof PGboxbase) { + PGboxbase otherbox = (PGboxbase) other; + return (compareLazyDim(this.llb, otherbox.llb) && compareLazyDim(this.urt, otherbox.urt)); + } + return false; + } + + /** + * Compare two coordinates with lazy dimension checking. + * + * As the Server always returns Box3D with three dimensions, z==0 equals + * dimensions==2 + * + */ + protected static boolean compareLazyDim(Point first, Point second) { + return first.x == second.x + && first.y == second.y + && (((first.dimension == 2 || first.z == 0.0) && (second.dimension == 2 || second.z == 0)) || (first.z == second.z)); + } + + public Object clone() { + PGboxbase obj = newInstance(); + obj.llb = this.llb; + obj.urt = this.urt; + obj.setType(type); + return obj; + } + + /** + * We could have used this.getClass().newInstance() here, but this forces us + * dealing with InstantiationException and IllegalAccessException. Due to + * the PGObject.clone() brokennes that does not allow clone() to throw + * CloneNotSupportedException, we cannot even pass this exceptions down to + * callers in a sane way. + */ + protected abstract PGboxbase newInstance(); +}