You can subscribe to this list here.
2001 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
(39) |
Dec
(70) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2002 |
Jan
(52) |
Feb
(168) |
Mar
(248) |
Apr
(143) |
May
(418) |
Jun
(558) |
Jul
(702) |
Aug
(311) |
Sep
(141) |
Oct
(350) |
Nov
(172) |
Dec
(182) |
2003 |
Jan
(320) |
Feb
(362) |
Mar
(356) |
Apr
(218) |
May
(447) |
Jun
(203) |
Jul
(745) |
Aug
(494) |
Sep
(175) |
Oct
(422) |
Nov
(554) |
Dec
(162) |
2004 |
Jan
(217) |
Feb
(353) |
Mar
(228) |
Apr
(407) |
May
(211) |
Jun
(270) |
Jul
(264) |
Aug
(198) |
Sep
(268) |
Oct
(227) |
Nov
(118) |
Dec
(47) |
2005 |
Jan
(207) |
Feb
(243) |
Mar
(297) |
Apr
(197) |
May
(281) |
Jun
(166) |
Jul
(164) |
Aug
(92) |
Sep
(155) |
Oct
(196) |
Nov
(189) |
Dec
(114) |
2006 |
Jan
(129) |
Feb
(219) |
Mar
(274) |
Apr
(213) |
May
(245) |
Jun
(220) |
Jul
(376) |
Aug
(347) |
Sep
(179) |
Oct
(493) |
Nov
(448) |
Dec
(339) |
2007 |
Jan
(304) |
Feb
(273) |
Mar
(237) |
Apr
(186) |
May
(215) |
Jun
(320) |
Jul
(229) |
Aug
(313) |
Sep
(331) |
Oct
(279) |
Nov
(347) |
Dec
(266) |
2008 |
Jan
(332) |
Feb
(280) |
Mar
(203) |
Apr
(277) |
May
(301) |
Jun
(356) |
Jul
(292) |
Aug
(203) |
Sep
(277) |
Oct
(142) |
Nov
(210) |
Dec
(239) |
2009 |
Jan
(250) |
Feb
(193) |
Mar
(174) |
Apr
(183) |
May
(342) |
Jun
(230) |
Jul
(292) |
Aug
(161) |
Sep
(204) |
Oct
(280) |
Nov
(281) |
Dec
(175) |
2010 |
Jan
(113) |
Feb
(106) |
Mar
(199) |
Apr
(166) |
May
(298) |
Jun
(147) |
Jul
(175) |
Aug
(192) |
Sep
(71) |
Oct
(79) |
Nov
(58) |
Dec
(55) |
2011 |
Jan
(83) |
Feb
(169) |
Mar
(142) |
Apr
(207) |
May
(311) |
Jun
(183) |
Jul
(218) |
Aug
(190) |
Sep
(158) |
Oct
(197) |
Nov
(93) |
Dec
(74) |
2012 |
Jan
(92) |
Feb
(50) |
Mar
(64) |
Apr
(45) |
May
(100) |
Jun
(70) |
Jul
(3) |
Aug
(1) |
Sep
(2) |
Oct
(5) |
Nov
(7) |
Dec
(4) |
2013 |
Jan
(6) |
Feb
(2) |
Mar
(2) |
Apr
(4) |
May
(3) |
Jun
|
Jul
(2) |
Aug
|
Sep
|
Oct
(1) |
Nov
(1) |
Dec
|
2014 |
Jan
(2) |
Feb
(2) |
Mar
(2) |
Apr
(3) |
May
(3) |
Jun
(1) |
Jul
|
Aug
(4) |
Sep
|
Oct
(1) |
Nov
(1) |
Dec
|
2015 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
(1) |
Jul
|
Aug
(1) |
Sep
|
Oct
|
Nov
(1) |
Dec
(1) |
2016 |
Jan
|
Feb
|
Mar
|
Apr
|
May
(1) |
Jun
(1) |
Jul
|
Aug
(3) |
Sep
|
Oct
|
Nov
(1) |
Dec
|
2017 |
Jan
(1) |
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
Author: jdeolive Date: 2012-05-28 15:58:36 -0700 (Mon, 28 May 2012) New Revision: 38770 Modified: trunk/modules/extension/xsd/xsd-gml3/src/main/java/org/geotools/gml3/GMLConfiguration.java trunk/modules/extension/xsd/xsd-gml3/src/main/java/org/geotools/gml3/bindings/AbstractGeometryTypeBinding.java trunk/modules/extension/xsd/xsd-gml3/src/main/java/org/geotools/gml3/bindings/EnvelopeTypeBinding.java trunk/modules/extension/xsd/xsd-gml3/src/main/java/org/geotools/gml3/v3_2/GMLConfiguration.java trunk/modules/extension/xsd/xsd-gml3/src/main/java/org/geotools/gml3/v3_2/bindings/EnvelopeTypeBinding.java trunk/modules/extension/xsd/xsd-gml3/src/test/java/org/geotools/gml3/GML3EncodingTest.java Log: GEOT-4152, option for skipping encoding of srsDimension Modified: trunk/modules/extension/xsd/xsd-gml3/src/main/java/org/geotools/gml3/GMLConfiguration.java =================================================================== --- trunk/modules/extension/xsd/xsd-gml3/src/main/java/org/geotools/gml3/GMLConfiguration.java 2012-05-28 02:37:52 UTC (rev 38769) +++ trunk/modules/extension/xsd/xsd-gml3/src/main/java/org/geotools/gml3/GMLConfiguration.java 2012-05-28 22:58:36 UTC (rev 38770) @@ -116,6 +116,12 @@ public static final QName ENCODE_FEATURE_MEMBER = org.geotools.gml2.GMLConfiguration.ENCODE_FEATURE_MEMBER; /** + * Boolean property which controls whether geometry and envelope objects are encoded with an + * srs dimension attribute. + */ + public static final QName NO_SRS_DIMENSION = new QName( "org.geotools.gml", "noSrsDimension" ); + + /** * extended support for arcs and surface flag */ boolean extArcSurfaceSupport = false; Modified: trunk/modules/extension/xsd/xsd-gml3/src/main/java/org/geotools/gml3/bindings/AbstractGeometryTypeBinding.java =================================================================== --- trunk/modules/extension/xsd/xsd-gml3/src/main/java/org/geotools/gml3/bindings/AbstractGeometryTypeBinding.java 2012-05-28 02:37:52 UTC (rev 38769) +++ trunk/modules/extension/xsd/xsd-gml3/src/main/java/org/geotools/gml3/bindings/AbstractGeometryTypeBinding.java 2012-05-28 22:58:36 UTC (rev 38770) @@ -20,7 +20,9 @@ import org.geotools.geometry.jts.coordinatesequence.CoordinateSequences; import org.geotools.gml3.GML; +import org.geotools.gml3.GMLConfiguration; import org.geotools.xml.AbstractComplexBinding; +import org.geotools.xml.Configuration; import org.geotools.xml.ElementInstance; import org.geotools.xml.Node; import org.opengis.referencing.crs.CoordinateReferenceSystem; @@ -67,6 +69,16 @@ * @source $URL$ */ public class AbstractGeometryTypeBinding extends AbstractComplexBinding { + Configuration config; + + public AbstractGeometryTypeBinding(Configuration config) { + this.config = config; + } + + public void setConfiguration(Configuration config) { + this.config = config; + } + /** * @generated */ @@ -117,6 +129,11 @@ } if ("srsDimension".equals(name.getLocalPart())) { + //check if srsDimension is turned off + if (config.hasProperty(GMLConfiguration.NO_SRS_DIMENSION)) { + return null; + } + /** * For the dimension, use the actual dimension of the geometry. Using * the dimension of the CRS is not sufficient, since currently CRSes Modified: trunk/modules/extension/xsd/xsd-gml3/src/main/java/org/geotools/gml3/bindings/EnvelopeTypeBinding.java =================================================================== --- trunk/modules/extension/xsd/xsd-gml3/src/main/java/org/geotools/gml3/bindings/EnvelopeTypeBinding.java 2012-05-28 02:37:52 UTC (rev 38769) +++ trunk/modules/extension/xsd/xsd-gml3/src/main/java/org/geotools/gml3/bindings/EnvelopeTypeBinding.java 2012-05-28 22:58:36 UTC (rev 38770) @@ -23,7 +23,9 @@ import org.geotools.geometry.jts.LiteCoordinateSequence; import org.geotools.geometry.jts.ReferencedEnvelope; import org.geotools.gml3.GML; +import org.geotools.gml3.GMLConfiguration; import org.geotools.xml.AbstractComplexBinding; +import org.geotools.xml.Configuration; import org.geotools.xml.ElementInstance; import org.geotools.xml.Node; import org.opengis.geometry.DirectPosition; @@ -86,6 +88,12 @@ * @source $URL$ */ public class EnvelopeTypeBinding extends AbstractComplexBinding { + Configuration config; + + public EnvelopeTypeBinding(Configuration config) { + this.config = config; + } + /** * @generated */ @@ -179,6 +187,11 @@ return GML3EncodingUtils.toURI(((ReferencedEnvelope) envelope) .getCoordinateReferenceSystem()); } else if (localName.equals("srsDimension")) { + //check if srsDimension is turned off + if (config.hasProperty(GMLConfiguration.NO_SRS_DIMENSION)) { + return null; + } + CoordinateReferenceSystem crs = ((ReferencedEnvelope) envelope) .getCoordinateReferenceSystem(); if (crs != null) { Modified: trunk/modules/extension/xsd/xsd-gml3/src/main/java/org/geotools/gml3/v3_2/GMLConfiguration.java =================================================================== --- trunk/modules/extension/xsd/xsd-gml3/src/main/java/org/geotools/gml3/v3_2/GMLConfiguration.java 2012-05-28 02:37:52 UTC (rev 38769) +++ trunk/modules/extension/xsd/xsd-gml3/src/main/java/org/geotools/gml3/v3_2/GMLConfiguration.java 2012-05-28 22:58:36 UTC (rev 38770) @@ -16,6 +16,8 @@ */ package org.geotools.gml3.v3_2; +import javax.xml.namespace.QName; + import org.geotools.gml2.bindings.GMLCoordinatesTypeBinding; import org.geotools.gml3.bindings.AbstractFeatureCollectionTypeBinding; import org.geotools.gml3.bindings.AbstractFeatureTypeBinding; @@ -84,6 +86,12 @@ public class GMLConfiguration extends Configuration { /** + * Boolean property which controls whether geometry and envelope objects are encoded with an + * srs dimension attribute. + */ + public static final QName NO_SRS_DIMENSION = org.geotools.gml3.GMLConfiguration.NO_SRS_DIMENSION; + + /** * Creates a new configuration. * * @generated Modified: trunk/modules/extension/xsd/xsd-gml3/src/main/java/org/geotools/gml3/v3_2/bindings/EnvelopeTypeBinding.java =================================================================== --- trunk/modules/extension/xsd/xsd-gml3/src/main/java/org/geotools/gml3/v3_2/bindings/EnvelopeTypeBinding.java 2012-05-28 02:37:52 UTC (rev 38769) +++ trunk/modules/extension/xsd/xsd-gml3/src/main/java/org/geotools/gml3/v3_2/bindings/EnvelopeTypeBinding.java 2012-05-28 22:58:36 UTC (rev 38770) @@ -19,9 +19,14 @@ import javax.xml.namespace.QName; import org.geotools.gml3.v3_2.GML; +import org.geotools.xml.Configuration; public class EnvelopeTypeBinding extends org.geotools.gml3.bindings.EnvelopeTypeBinding { + public EnvelopeTypeBinding(Configuration config) { + super(config); + } + @Override public QName getTarget() { return GML.EnvelopeType; Modified: trunk/modules/extension/xsd/xsd-gml3/src/test/java/org/geotools/gml3/GML3EncodingTest.java =================================================================== --- trunk/modules/extension/xsd/xsd-gml3/src/test/java/org/geotools/gml3/GML3EncodingTest.java 2012-05-28 02:37:52 UTC (rev 38769) +++ trunk/modules/extension/xsd/xsd-gml3/src/test/java/org/geotools/gml3/GML3EncodingTest.java 2012-05-28 22:58:36 UTC (rev 38770) @@ -193,4 +193,14 @@ assertEquals( 0, dom.getElementsByTagName("gml:boundedBy").getLength()); } + + public void testEncodeWithNoSrsDimension() throws Exception { + GMLConfiguration gml = new GMLConfiguration(); + Document dom = new Encoder(gml).encodeAsDOM(GML3MockData.point(), GML.Point); + assertTrue(dom.getDocumentElement().hasAttribute("srsDimension")); + + gml.getProperties().add(GMLConfiguration.NO_SRS_DIMENSION); + dom = new Encoder(gml).encodeAsDOM(GML3MockData.point(), GML.Point); + assertFalse(dom.getDocumentElement().hasAttribute("srsDimension")); + } } |
From: <svn...@os...> - 2012-05-28 02:38:00
|
Author: ang05a Date: 2012-05-27 19:37:52 -0700 (Sun, 27 May 2012) New Revision: 38769 Modified: trunk/docs/user/advanced/build/source.rst Log: Point svn config to the version controlled one (build/subversion/config). Modified: trunk/docs/user/advanced/build/source.rst =================================================================== --- trunk/docs/user/advanced/build/source.rst 2012-05-27 19:31:43 UTC (rev 38768) +++ trunk/docs/user/advanced/build/source.rst 2012-05-28 02:37:52 UTC (rev 38769) @@ -32,7 +32,7 @@ 1. Our Subversion Install page contains detailed instructions for setting up subversion on different platforms. -2. Copy :download:`config</artifacts/config>` into the following location +2. Copy :download:`config</../../build/subversion/config>` into the following location ============= =========================================================================== Plartform Config File Location |
From: <svn...@os...> - 2012-05-27 19:31:50
|
Author: aaime Date: 2012-05-27 12:31:43 -0700 (Sun, 27 May 2012) New Revision: 38768 Modified: branches/2.7.x/modules/library/referencing/src/main/java/org/geotools/referencing/factory/epsg/AuthorityCodes.java branches/2.7.x/modules/library/referencing/src/main/java/org/geotools/referencing/factory/epsg/DirectEpsgFactory.java branches/2.7.x/modules/plugin/epsg-hsql/src/main/java/org/geotools/referencing/factory/epsg/FactoryUsingHSQL.java branches/2.7.x/modules/plugin/epsg-hsql/src/main/java/org/geotools/referencing/factory/epsg/ThreadedHsqlEpsgFactory.java branches/2.7.x/modules/plugin/epsg-hsql/src/test/java/org/geotools/referencing/factory/epsg/ThreadedHsqlEpsgFactoryTest.java Log: [GEOT-4061] EPSG HSQL factories cannot recover from connection corruption Modified: branches/2.7.x/modules/library/referencing/src/main/java/org/geotools/referencing/factory/epsg/AuthorityCodes.java =================================================================== --- branches/2.7.x/modules/library/referencing/src/main/java/org/geotools/referencing/factory/epsg/AuthorityCodes.java 2012-05-27 19:10:34 UTC (rev 38767) +++ branches/2.7.x/modules/library/referencing/src/main/java/org/geotools/referencing/factory/epsg/AuthorityCodes.java 2012-05-27 19:31:43 UTC (rev 38768) @@ -108,12 +108,6 @@ private transient PreparedStatement querySingle; /** - * The connection to the underlying database. - */ - private Connection connection; - - - /** * The collection's size, or a negative value if not yet computed. The records will be counted * only when first needed. The special value -2 if set by {@link #isEmpty} if the size has not * yet been computed, but we know that the set is not empty. @@ -164,30 +158,48 @@ buffer.append(hasWhere ? " AND " : " WHERE ").append(table.codeColumn).append(" = ?"); sqlSingle = factory.adaptSQL(buffer.toString()); } + + protected PreparedStatement validateStatement(PreparedStatement stmt, String sql) throws SQLException { + Connection conn = null; + if (stmt != null) { + try { + conn = stmt.getConnection(); + } catch (SQLException sqle) { + // mark this invalid + stmt = null; + } + } + if(conn != null && !factory.isConnectionValid(conn)) { + stmt = null; + } + if (stmt == null) { + stmt = factory.getConnection().prepareStatement(sql); + } + return stmt; + } /** * Returns all codes. */ private ResultSet getAll() throws SQLException { assert Thread.holdsLock(this); - if (queryAll != null && factory.isConnectionValid(queryAll.getConnection())) { - try { - return queryAll.executeQuery(); - } catch (SQLException ignore) { - /* - * Failed to reuse an existing statement. This problem occurs in some occasions - * with the JDBC-ODBC bridge in Java 6 (the error message is "Invalid handle"). - * I'm not sure where the bug come from (didn't noticed it when using HSQL). We - * will try again with a new statement created in the code after this 'catch' - * clause. Note that we set 'queryAll' to null first in case of failure during - * the 'prepareStatement(...)' execution. - */ - queryAll.close(); - queryAll = null; - recoverableException("getAll", ignore); - } + queryAll = validateStatement(queryAll, sqlAll); + try { + return queryAll.executeQuery(); + } catch (SQLException ignore) { + /* + * Failed to reuse an existing statement. This problem occurs in some occasions + * with the JDBC-ODBC bridge in Java 6 (the error message is "Invalid handle"). + * I'm not sure where the bug come from (didn't noticed it when using HSQL). We + * will try again with a new statement created in the code after this 'catch' + * clause. Note that we set 'queryAll' to null first in case of failure during + * the 'prepareStatement(...)' execution. + */ + queryAll.close(); + queryAll = null; + recoverableException("getAll", ignore); } - queryAll = factory.getConnection().prepareStatement(sqlAll); + queryAll = validateStatement(queryAll, sqlAll); return queryAll.executeQuery(); } @@ -196,9 +208,7 @@ */ private ResultSet getSingle(final Object code) throws SQLException { assert Thread.holdsLock(this); - if (querySingle == null || !factory.isConnectionValid(querySingle.getConnection())) { - querySingle = factory.getConnection().prepareStatement(sqlSingle); - } + querySingle = validateStatement(querySingle, sqlSingle); querySingle.setString(1, code.toString()); return querySingle.executeQuery(); } Modified: branches/2.7.x/modules/library/referencing/src/main/java/org/geotools/referencing/factory/epsg/DirectEpsgFactory.java =================================================================== --- branches/2.7.x/modules/library/referencing/src/main/java/org/geotools/referencing/factory/epsg/DirectEpsgFactory.java 2012-05-27 19:10:34 UTC (rev 38767) +++ branches/2.7.x/modules/library/referencing/src/main/java/org/geotools/referencing/factory/epsg/DirectEpsgFactory.java 2012-05-27 19:31:43 UTC (rev 38768) @@ -710,14 +710,21 @@ { assert Thread.holdsLock(this); PreparedStatement stmt = statements.get(key); - if(stmt != null && !isConnectionValid(stmt.getConnection())) + Connection conn = null; + if (stmt != null) { + try { + conn = stmt.getConnection(); + } catch (SQLException sqle) { + // mark this invalid + stmt = null; + } + } + if(conn != null && !isConnectionValid(conn)) stmt = null; if (stmt == null) { stmt = getConnection().prepareStatement(adaptSQL(sql)); statements.put(key, stmt); - } else { - - } + } return stmt; } @@ -3184,7 +3191,7 @@ if (connection == null) { connection = dataSource.getConnection(); } else { - if(!isConnectionValid(connection)) { + if(connection.isClosed() || !isConnectionValid(connection)) { statements.clear(); try { // we need to send back the connection to the eventual Modified: branches/2.7.x/modules/plugin/epsg-hsql/src/main/java/org/geotools/referencing/factory/epsg/FactoryUsingHSQL.java =================================================================== --- branches/2.7.x/modules/plugin/epsg-hsql/src/main/java/org/geotools/referencing/factory/epsg/FactoryUsingHSQL.java 2012-05-27 19:10:34 UTC (rev 38767) +++ branches/2.7.x/modules/plugin/epsg-hsql/src/main/java/org/geotools/referencing/factory/epsg/FactoryUsingHSQL.java 2012-05-27 19:31:43 UTC (rev 38768) @@ -22,6 +22,7 @@ import java.sql.SQLException; import java.util.regex.Pattern; import java.util.regex.Matcher; +import javax.sql.DataSource; // Geotools dependencies import org.geotools.factory.Hints; @@ -53,7 +54,11 @@ public FactoryUsingHSQL(final Hints hints, final Connection connection) { super(hints, connection); } - + + public FactoryUsingHSQL(final Hints hints, final DataSource dataSource) { + super(hints, dataSource); + } + /** * If the query contains a "FROM (" expression, remove the parenthesis. */ Modified: branches/2.7.x/modules/plugin/epsg-hsql/src/main/java/org/geotools/referencing/factory/epsg/ThreadedHsqlEpsgFactory.java =================================================================== --- branches/2.7.x/modules/plugin/epsg-hsql/src/main/java/org/geotools/referencing/factory/epsg/ThreadedHsqlEpsgFactory.java 2012-05-27 19:10:34 UTC (rev 38767) +++ branches/2.7.x/modules/plugin/epsg-hsql/src/main/java/org/geotools/referencing/factory/epsg/ThreadedHsqlEpsgFactory.java 2012-05-27 19:31:43 UTC (rev 38768) @@ -325,7 +325,7 @@ } } - FactoryUsingHSQL factory = new FactoryUsingHSQL(hints, getDataSource().getConnection()); + FactoryUsingHSQL factory = new FactoryUsingHSQL(hints, getDataSource()); factory.setValidationQuery("CALL NOW()"); return factory; } Modified: branches/2.7.x/modules/plugin/epsg-hsql/src/test/java/org/geotools/referencing/factory/epsg/ThreadedHsqlEpsgFactoryTest.java =================================================================== --- branches/2.7.x/modules/plugin/epsg-hsql/src/test/java/org/geotools/referencing/factory/epsg/ThreadedHsqlEpsgFactoryTest.java 2012-05-27 19:10:34 UTC (rev 38767) +++ branches/2.7.x/modules/plugin/epsg-hsql/src/test/java/org/geotools/referencing/factory/epsg/ThreadedHsqlEpsgFactoryTest.java 2012-05-27 19:31:43 UTC (rev 38768) @@ -16,6 +16,7 @@ */ package org.geotools.referencing.factory.epsg; +import java.lang.reflect.Method; import static org.junit.Assert.*; import java.util.Set; @@ -62,7 +63,32 @@ if( finder == null ){ finder = factory.getIdentifiedObjectFinder(CoordinateReferenceSystem.class); } + corruptConnection(); } + + @Test + public void testConnectionCorruption() throws Exception { + corruptConnection(); + CRS.decode("EPSG:4326"); + } + + @Test + public void testConnectionCorruptionListAll() throws Exception { + Set<String> original = CRS.getSupportedCodes("EPSG"); + assertTrue(original.size() > 4000); + corruptConnection(); + Set<String> afterCorruption = CRS.getSupportedCodes("EPSG"); + assertEquals(original, afterCorruption); + } + + private void corruptConnection() throws Exception { + java.lang.reflect.Field field = org.geotools.referencing.factory.BufferedAuthorityFactory.class.getDeclaredField("backingStore"); + field.setAccessible(true); + Object def = field.get(factory); + Method getConnection = DirectEpsgFactory.class.getDeclaredMethod("getConnection"); + java.sql.Connection conn = (java.sql.Connection) getConnection.invoke( def ); + conn.close(); + } @Test public void testCreation() throws Exception { |
From: <svn...@os...> - 2012-05-27 19:10:43
|
Author: aaime Date: 2012-05-27 12:10:34 -0700 (Sun, 27 May 2012) New Revision: 38767 Modified: trunk/modules/library/referencing/src/main/java/org/geotools/referencing/factory/epsg/AuthorityCodes.java trunk/modules/library/referencing/src/main/java/org/geotools/referencing/factory/epsg/DirectEpsgFactory.java trunk/modules/plugin/epsg-hsql/src/main/java/org/geotools/referencing/factory/epsg/FactoryUsingHSQL.java trunk/modules/plugin/epsg-hsql/src/main/java/org/geotools/referencing/factory/epsg/ThreadedHsqlEpsgFactory.java trunk/modules/plugin/epsg-hsql/src/test/java/org/geotools/referencing/factory/epsg/ThreadedHsqlEpsgFactoryTest.java Log: [GEOT-4061] EPSG HSQL factories cannot recover from connection corruption Modified: trunk/modules/library/referencing/src/main/java/org/geotools/referencing/factory/epsg/AuthorityCodes.java =================================================================== --- trunk/modules/library/referencing/src/main/java/org/geotools/referencing/factory/epsg/AuthorityCodes.java 2012-05-27 17:29:51 UTC (rev 38766) +++ trunk/modules/library/referencing/src/main/java/org/geotools/referencing/factory/epsg/AuthorityCodes.java 2012-05-27 19:10:34 UTC (rev 38767) @@ -108,12 +108,6 @@ private transient PreparedStatement querySingle; /** - * The connection to the underlying database. - */ - private Connection connection; - - - /** * The collection's size, or a negative value if not yet computed. The records will be counted * only when first needed. The special value -2 if set by {@link #isEmpty} if the size has not * yet been computed, but we know that the set is not empty. @@ -164,30 +158,48 @@ buffer.append(hasWhere ? " AND " : " WHERE ").append(table.codeColumn).append(" = ?"); sqlSingle = factory.adaptSQL(buffer.toString()); } + + protected PreparedStatement validateStatement(PreparedStatement stmt, String sql) throws SQLException { + Connection conn = null; + if (stmt != null) { + try { + conn = stmt.getConnection(); + } catch (SQLException sqle) { + // mark this invalid + stmt = null; + } + } + if(conn != null && !factory.isConnectionValid(conn)) { + stmt = null; + } + if (stmt == null) { + stmt = factory.getConnection().prepareStatement(sql); + } + return stmt; + } /** * Returns all codes. */ private ResultSet getAll() throws SQLException { assert Thread.holdsLock(this); - if (queryAll != null && factory.isConnectionValid(queryAll.getConnection())) { - try { - return queryAll.executeQuery(); - } catch (SQLException ignore) { - /* - * Failed to reuse an existing statement. This problem occurs in some occasions - * with the JDBC-ODBC bridge in Java 6 (the error message is "Invalid handle"). - * I'm not sure where the bug come from (didn't noticed it when using HSQL). We - * will try again with a new statement created in the code after this 'catch' - * clause. Note that we set 'queryAll' to null first in case of failure during - * the 'prepareStatement(...)' execution. - */ - queryAll.close(); - queryAll = null; - recoverableException("getAll", ignore); - } + queryAll = validateStatement(queryAll, sqlAll); + try { + return queryAll.executeQuery(); + } catch (SQLException ignore) { + /* + * Failed to reuse an existing statement. This problem occurs in some occasions + * with the JDBC-ODBC bridge in Java 6 (the error message is "Invalid handle"). + * I'm not sure where the bug come from (didn't noticed it when using HSQL). We + * will try again with a new statement created in the code after this 'catch' + * clause. Note that we set 'queryAll' to null first in case of failure during + * the 'prepareStatement(...)' execution. + */ + queryAll.close(); + queryAll = null; + recoverableException("getAll", ignore); } - queryAll = factory.getConnection().prepareStatement(sqlAll); + queryAll = validateStatement(queryAll, sqlAll); return queryAll.executeQuery(); } @@ -196,9 +208,7 @@ */ private ResultSet getSingle(final Object code) throws SQLException { assert Thread.holdsLock(this); - if (querySingle == null || !factory.isConnectionValid(querySingle.getConnection())) { - querySingle = factory.getConnection().prepareStatement(sqlSingle); - } + querySingle = validateStatement(querySingle, sqlSingle); querySingle.setString(1, code.toString()); return querySingle.executeQuery(); } Modified: trunk/modules/library/referencing/src/main/java/org/geotools/referencing/factory/epsg/DirectEpsgFactory.java =================================================================== --- trunk/modules/library/referencing/src/main/java/org/geotools/referencing/factory/epsg/DirectEpsgFactory.java 2012-05-27 17:29:51 UTC (rev 38766) +++ trunk/modules/library/referencing/src/main/java/org/geotools/referencing/factory/epsg/DirectEpsgFactory.java 2012-05-27 19:10:34 UTC (rev 38767) @@ -711,14 +711,21 @@ { assert Thread.holdsLock(this); PreparedStatement stmt = statements.get(key); - if(stmt != null && !isConnectionValid(stmt.getConnection())) + Connection conn = null; + if (stmt != null) { + try { + conn = stmt.getConnection(); + } catch (SQLException sqle) { + // mark this invalid + stmt = null; + } + } + if(conn != null && !isConnectionValid(conn)) stmt = null; if (stmt == null) { stmt = getConnection().prepareStatement(adaptSQL(sql)); statements.put(key, stmt); - } else { - - } + } return stmt; } @@ -3188,7 +3195,7 @@ if (connection == null) { connection = dataSource.getConnection(); } else { - if(!isConnectionValid(connection)) { + if(connection.isClosed() || !isConnectionValid(connection)) { statements.clear(); try { // we need to send back the connection to the eventual Modified: trunk/modules/plugin/epsg-hsql/src/main/java/org/geotools/referencing/factory/epsg/FactoryUsingHSQL.java =================================================================== --- trunk/modules/plugin/epsg-hsql/src/main/java/org/geotools/referencing/factory/epsg/FactoryUsingHSQL.java 2012-05-27 17:29:51 UTC (rev 38766) +++ trunk/modules/plugin/epsg-hsql/src/main/java/org/geotools/referencing/factory/epsg/FactoryUsingHSQL.java 2012-05-27 19:10:34 UTC (rev 38767) @@ -22,6 +22,7 @@ import java.sql.SQLException; import java.util.regex.Pattern; import java.util.regex.Matcher; +import javax.sql.DataSource; // Geotools dependencies import org.geotools.factory.Hints; @@ -53,7 +54,11 @@ public FactoryUsingHSQL(final Hints hints, final Connection connection) { super(hints, connection); } - + + public FactoryUsingHSQL(final Hints hints, final DataSource dataSource) { + super(hints, dataSource); + } + /** * If the query contains a "FROM (" expression, remove the parenthesis. */ Modified: trunk/modules/plugin/epsg-hsql/src/main/java/org/geotools/referencing/factory/epsg/ThreadedHsqlEpsgFactory.java =================================================================== --- trunk/modules/plugin/epsg-hsql/src/main/java/org/geotools/referencing/factory/epsg/ThreadedHsqlEpsgFactory.java 2012-05-27 17:29:51 UTC (rev 38766) +++ trunk/modules/plugin/epsg-hsql/src/main/java/org/geotools/referencing/factory/epsg/ThreadedHsqlEpsgFactory.java 2012-05-27 19:10:34 UTC (rev 38767) @@ -326,7 +326,7 @@ } } - FactoryUsingHSQL factory = new FactoryUsingHSQL(hints, getDataSource().getConnection()); + FactoryUsingHSQL factory = new FactoryUsingHSQL(hints, getDataSource()); factory.setValidationQuery("CALL NOW()"); return factory; } Modified: trunk/modules/plugin/epsg-hsql/src/test/java/org/geotools/referencing/factory/epsg/ThreadedHsqlEpsgFactoryTest.java =================================================================== --- trunk/modules/plugin/epsg-hsql/src/test/java/org/geotools/referencing/factory/epsg/ThreadedHsqlEpsgFactoryTest.java 2012-05-27 17:29:51 UTC (rev 38766) +++ trunk/modules/plugin/epsg-hsql/src/test/java/org/geotools/referencing/factory/epsg/ThreadedHsqlEpsgFactoryTest.java 2012-05-27 19:10:34 UTC (rev 38767) @@ -16,6 +16,7 @@ */ package org.geotools.referencing.factory.epsg; +import java.lang.reflect.Method; import static org.junit.Assert.*; import java.util.Set; @@ -63,7 +64,32 @@ if( finder == null ){ finder = factory.getIdentifiedObjectFinder(CoordinateReferenceSystem.class); } + corruptConnection(); } + + @Test + public void testConnectionCorruption() throws Exception { + corruptConnection(); + CRS.decode("EPSG:4326"); + } + + @Test + public void testConnectionCorruptionListAll() throws Exception { + Set<String> original = CRS.getSupportedCodes("EPSG"); + assertTrue(original.size() > 4000); + corruptConnection(); + Set<String> afterCorruption = CRS.getSupportedCodes("EPSG"); + assertEquals(original, afterCorruption); + } + + private void corruptConnection() throws Exception { + java.lang.reflect.Field field = org.geotools.referencing.factory.BufferedAuthorityFactory.class.getDeclaredField("backingStore"); + field.setAccessible(true); + Object def = field.get(factory); + Method getConnection = DirectEpsgFactory.class.getDeclaredMethod("getConnection"); + java.sql.Connection conn = (java.sql.Connection) getConnection.invoke( def ); + conn.close(); + } @Test public void testCreation() throws Exception { |
Author: aaime Date: 2012-05-27 10:29:51 -0700 (Sun, 27 May 2012) New Revision: 38766 Added: branches/2.7.x/modules/library/main/src/main/java/org/geotools/filter/function/FilterFunction_setCRS.java branches/2.7.x/modules/library/main/src/test/java/org/geotools/filter/function/FilterFunction_setCRSTest.java Modified: branches/2.7.x/modules/library/main/src/main/resources/META-INF/services/org.opengis.filter.expression.Function Log: [GEOT-4157] New filter function to set the CRS in a geometry Added: branches/2.7.x/modules/library/main/src/main/java/org/geotools/filter/function/FilterFunction_setCRS.java =================================================================== --- branches/2.7.x/modules/library/main/src/main/java/org/geotools/filter/function/FilterFunction_setCRS.java (rev 0) +++ branches/2.7.x/modules/library/main/src/main/java/org/geotools/filter/function/FilterFunction_setCRS.java 2012-05-27 17:29:51 UTC (rev 38766) @@ -0,0 +1,69 @@ +package org.geotools.filter.function; + +/* + * GeoTools - The Open Source Java GIS Toolkit + * http://geotools.org + * + * (C) 2005-2008, Open Source Geospatial Foundation (OSGeo) + * + * 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; + * 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. + */ +import org.geotools.filter.FunctionExpressionImpl; +import org.geotools.referencing.CRS; +import org.opengis.referencing.FactoryException; +import org.opengis.referencing.crs.CoordinateReferenceSystem; + +import com.vividsolutions.jts.geom.Geometry; + +public class FilterFunction_setCRS extends FunctionExpressionImpl { + + public FilterFunction_setCRS() { + super("setCRS"); + } + + public int getArgCount() { + return 2; + } + + public Object evaluate(Object feature) { + Geometry geom; + CoordinateReferenceSystem crs; + + try { // attempt to get value and perform conversion + geom = (Geometry) getExpression(0).evaluate(feature, Geometry.class); + } catch (Exception e) // probably a type error + { + throw new IllegalArgumentException( + "Expected argument of type Geometry for argument #0"); + } + + try { // try to parse the SRS + crs = getExpression(1).evaluate(feature, CoordinateReferenceSystem.class); + if(crs == null) { + String srs = getExpression(1).evaluate(feature, String.class); + try { + crs = CRS.decode(srs); + } catch(FactoryException e) { + crs = CRS.parseWKT(srs); + } + } + } catch(Exception e) { + throw new IllegalArgumentException( + "Expected argument of type CoordinateReferenceSystem, WKT or valid EPSG code for argument #1"); + } + + if(geom != null) { + geom.setUserData(crs); + } + + return geom; + } +} Modified: branches/2.7.x/modules/library/main/src/main/resources/META-INF/services/org.opengis.filter.expression.Function =================================================================== --- branches/2.7.x/modules/library/main/src/main/resources/META-INF/services/org.opengis.filter.expression.Function 2012-05-27 17:23:31 UTC (rev 38765) +++ branches/2.7.x/modules/library/main/src/main/resources/META-INF/services/org.opengis.filter.expression.Function 2012-05-27 17:29:51 UTC (rev 38766) @@ -23,6 +23,7 @@ org.geotools.filter.function.FilterFunction_intersects org.geotools.filter.function.FilterFunction_isClosed org.geotools.filter.function.FilterFunction_geomFromWKT +org.geotools.filter.function.FilterFunction_setCRS org.geotools.filter.function.FilterFunction_toWKT org.geotools.filter.function.FilterFunction_geomLength org.geotools.filter.function.FilterFunction_isValid Added: branches/2.7.x/modules/library/main/src/test/java/org/geotools/filter/function/FilterFunction_setCRSTest.java =================================================================== --- branches/2.7.x/modules/library/main/src/test/java/org/geotools/filter/function/FilterFunction_setCRSTest.java (rev 0) +++ branches/2.7.x/modules/library/main/src/test/java/org/geotools/filter/function/FilterFunction_setCRSTest.java 2012-05-27 17:29:51 UTC (rev 38766) @@ -0,0 +1,45 @@ +package org.geotools.filter.function; + +import static org.junit.Assert.*; + +import org.geotools.factory.CommonFactoryFinder; +import org.geotools.referencing.CRS; +import org.geotools.referencing.crs.DefaultGeographicCRS; +import org.junit.Before; +import org.junit.Test; +import org.opengis.filter.FilterFactory2; +import org.opengis.filter.expression.Function; + +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.io.WKTReader; + +public class FilterFunction_setCRSTest { + FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2(null); + Geometry g; + + @Before + public void setup() throws Exception { + g = new WKTReader().read("POINT(0 0)"); + } + + @Test + public void setCRSObject() { + Function f = ff.function("setCRS", ff.literal(g), ff.literal(DefaultGeographicCRS.WGS84)); + Geometry sg = (Geometry) f.evaluate(null); + assertEquals(DefaultGeographicCRS.WGS84, sg.getUserData()); + } + + @Test + public void setCRSCode() throws Exception { + Function f = ff.function("setCRS", ff.literal(g), ff.literal("EPSG:4326")); + Geometry sg = (Geometry) f.evaluate(null); + assertEquals(CRS.decode("EPSG:4326"), sg.getUserData()); + } + + @Test + public void setCRSWkt() { + Function f = ff.function("setCRS", ff.literal(g), ff.literal(DefaultGeographicCRS.WGS84.toWKT())); + Geometry sg = (Geometry) f.evaluate(null); + assertTrue(CRS.equalsIgnoreMetadata(DefaultGeographicCRS.WGS84, sg.getUserData())); + } +} |
Author: aaime Date: 2012-05-27 10:23:31 -0700 (Sun, 27 May 2012) New Revision: 38765 Added: trunk/modules/library/main/src/main/java/org/geotools/filter/function/FilterFunction_setCRS.java trunk/modules/library/main/src/test/java/org/geotools/filter/function/FilterFunction_setCRSTest.java Modified: trunk/modules/library/main/src/main/resources/META-INF/services/org.opengis.filter.expression.Function Log: [GEOT-4157] New filter function to set the CRS in a geometry Added: trunk/modules/library/main/src/main/java/org/geotools/filter/function/FilterFunction_setCRS.java =================================================================== --- trunk/modules/library/main/src/main/java/org/geotools/filter/function/FilterFunction_setCRS.java (rev 0) +++ trunk/modules/library/main/src/main/java/org/geotools/filter/function/FilterFunction_setCRS.java 2012-05-27 17:23:31 UTC (rev 38765) @@ -0,0 +1,77 @@ +package org.geotools.filter.function; + +/* + * GeoTools - The Open Source Java GIS Toolkit + * http://geotools.org + * + * (C) 2005-2008, Open Source Geospatial Foundation (OSGeo) + * + * 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; + * 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. + */ +import static org.geotools.filter.capability.FunctionNameImpl.parameter; + +import org.geotools.filter.FunctionExpressionImpl; +import org.geotools.filter.capability.FunctionNameImpl; +import org.geotools.referencing.CRS; +import org.opengis.filter.capability.FunctionName; +import org.opengis.referencing.FactoryException; +import org.opengis.referencing.crs.CoordinateReferenceSystem; + +import com.vividsolutions.jts.geom.Geometry; + +public class FilterFunction_setCRS extends FunctionExpressionImpl { + + public static FunctionName NAME = new FunctionNameImpl("setCRS", Geometry.class, + parameter("geometry", Geometry.class), parameter("CRS", String.class)); + + public FilterFunction_setCRS() { + super("setSRS"); + functionName = NAME; + } + + public int getArgCount() { + return 2; + } + + public Object evaluate(Object feature) { + Geometry geom; + CoordinateReferenceSystem crs; + + try { // attempt to get value and perform conversion + geom = (Geometry) getExpression(0).evaluate(feature, Geometry.class); + } catch (Exception e) // probably a type error + { + throw new IllegalArgumentException( + "Expected argument of type Geometry for argument #0"); + } + + try { // try to parse the SRS + crs = getExpression(1).evaluate(feature, CoordinateReferenceSystem.class); + if(crs == null) { + String srs = getExpression(1).evaluate(feature, String.class); + try { + crs = CRS.decode(srs); + } catch(FactoryException e) { + crs = CRS.parseWKT(srs); + } + } + } catch(Exception e) { + throw new IllegalArgumentException( + "Expected argument of type CoordinateReferenceSystem, WKT or valid EPSG code for argument #1"); + } + + if(geom != null) { + geom.setUserData(crs); + } + + return geom; + } +} Modified: trunk/modules/library/main/src/main/resources/META-INF/services/org.opengis.filter.expression.Function =================================================================== --- trunk/modules/library/main/src/main/resources/META-INF/services/org.opengis.filter.expression.Function 2012-05-27 09:20:15 UTC (rev 38764) +++ trunk/modules/library/main/src/main/resources/META-INF/services/org.opengis.filter.expression.Function 2012-05-27 17:23:31 UTC (rev 38765) @@ -23,6 +23,7 @@ org.geotools.filter.function.FilterFunction_intersects org.geotools.filter.function.FilterFunction_isClosed org.geotools.filter.function.FilterFunction_geomFromWKT +org.geotools.filter.function.FilterFunction_setCRS org.geotools.filter.function.FilterFunction_toWKT org.geotools.filter.function.FilterFunction_geomLength org.geotools.filter.function.FilterFunction_isValid Added: trunk/modules/library/main/src/test/java/org/geotools/filter/function/FilterFunction_setCRSTest.java =================================================================== --- trunk/modules/library/main/src/test/java/org/geotools/filter/function/FilterFunction_setCRSTest.java (rev 0) +++ trunk/modules/library/main/src/test/java/org/geotools/filter/function/FilterFunction_setCRSTest.java 2012-05-27 17:23:31 UTC (rev 38765) @@ -0,0 +1,45 @@ +package org.geotools.filter.function; + +import static org.junit.Assert.*; + +import org.geotools.factory.CommonFactoryFinder; +import org.geotools.referencing.CRS; +import org.geotools.referencing.crs.DefaultGeographicCRS; +import org.junit.Before; +import org.junit.Test; +import org.opengis.filter.FilterFactory2; +import org.opengis.filter.expression.Function; + +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.io.WKTReader; + +public class FilterFunction_setCRSTest { + FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2(); + Geometry g; + + @Before + public void setup() throws Exception { + g = new WKTReader().read("POINT(0 0)"); + } + + @Test + public void setCRSObject() { + Function f = ff.function("setCRS", ff.literal(g), ff.literal(DefaultGeographicCRS.WGS84)); + Geometry sg = (Geometry) f.evaluate(null); + assertEquals(DefaultGeographicCRS.WGS84, sg.getUserData()); + } + + @Test + public void setCRSCode() throws Exception { + Function f = ff.function("setCRS", ff.literal(g), ff.literal("EPSG:4326")); + Geometry sg = (Geometry) f.evaluate(null); + assertEquals(CRS.decode("EPSG:4326"), sg.getUserData()); + } + + @Test + public void setCRSWkt() { + Function f = ff.function("setCRS", ff.literal(g), ff.literal(DefaultGeographicCRS.WGS84.toWKT())); + Geometry sg = (Geometry) f.evaluate(null); + assertTrue(CRS.equalsIgnoreMetadata(DefaultGeographicCRS.WGS84, sg.getUserData())); + } +} |
From: <svn...@os...> - 2012-05-27 09:20:22
|
Author: aaime Date: 2012-05-27 02:20:15 -0700 (Sun, 27 May 2012) New Revision: 38764 Modified: trunk/modules/library/render/src/main/java/org/geotools/renderer/lite/StreamingRenderer.java trunk/modules/library/render/src/test/java/org/geotools/renderer/lite/SpatialFilterTest.java Log: GEOT-4155, applied also to layer definition queries Modified: trunk/modules/library/render/src/main/java/org/geotools/renderer/lite/StreamingRenderer.java =================================================================== --- trunk/modules/library/render/src/main/java/org/geotools/renderer/lite/StreamingRenderer.java 2012-05-27 09:12:50 UTC (rev 38763) +++ trunk/modules/library/render/src/main/java/org/geotools/renderer/lite/StreamingRenderer.java 2012-05-27 09:20:15 UTC (rev 38764) @@ -138,6 +138,7 @@ import org.opengis.parameter.GeneralParameterValue; import org.opengis.parameter.ParameterValueGroup; import org.opengis.referencing.FactoryException; +import org.opengis.referencing.NoSuchAuthorityCodeException; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.datum.PixelInCell; import org.opengis.referencing.operation.MathTransform; @@ -964,7 +965,7 @@ CoordinateReferenceSystem featCrs, Rectangle screenSize, GeometryDescriptor geometryAttribute, AffineTransform worldToScreenTransform) - throws IllegalFilterException, IOException { + throws IllegalFilterException, IOException, FactoryException { FeatureCollection<FeatureType, Feature> results = null; Query query = new Query(Query.ALL); Query definitionQuery; @@ -1057,7 +1058,7 @@ // sure to respect it by combining it with the bounding box one. // Currently this definition query is being set dynamically in geoserver // as per the user's filter, maxFeatures and startIndex WMS GetMap custom parameters - definitionQuery = currLayer.getQuery(); + definitionQuery = reprojectQuery(currLayer.getQuery(), source); if (definitionQuery != Query.ALL) { if (query == Query.ALL) { @@ -1130,7 +1131,6 @@ return query; } - /** * Takes care of eventual geometric transformations * @param styles @@ -2336,8 +2336,24 @@ * @throws FactoryException */ void reprojectSpatialFilters(final ArrayList<LiteFeatureTypeStyle> lfts, FeatureSource fs) throws FactoryException { + FeatureType schema = fs.getSchema(); + CoordinateReferenceSystem declaredCRS = getDeclaredSRS(schema); + + // reproject spatial filters in each fts + for (LiteFeatureTypeStyle fts : lfts) { + reprojectSpatialFilters(fts, declaredCRS, schema); + } + } + + /** + * Computes the declared SRS of a layer based on the layer schema and the EPSG forcing flag + * @param schema + * @return + * @throws FactoryException + * @throws NoSuchAuthorityCodeException + */ + private CoordinateReferenceSystem getDeclaredSRS(FeatureType schema) throws FactoryException { // compute the default SRS of the feature source - FeatureType schema = fs.getSchema(); CoordinateReferenceSystem declaredCRS = schema.getCoordinateReferenceSystem(); if(isEPSGAxisOrderForced()) { Integer code = CRS.lookupEpsgCode(declaredCRS, false); @@ -2345,11 +2361,34 @@ declaredCRS = CRS.decode("urn:ogc:def:crs:EPSG::" + code); } } - - // reproject spatial filters in each fts - for (LiteFeatureTypeStyle fts : lfts) { - reprojectSpatialFilters(fts, declaredCRS, schema); + return declaredCRS; + } + + /** + * Reprojects all spatial filters in the specified Query so that they match the native srs of the + * specified feature source + * + * @param query + * @param source + * @return + * @throws FactoryException + */ + private Query reprojectQuery(Query query, FeatureSource<FeatureType, Feature> source) throws FactoryException { + if(query == null || query.getFilter() == null) { + return query; } + + // compute the declared CRS + Filter original = query.getFilter(); + CoordinateReferenceSystem declaredCRS = getDeclaredSRS(source.getSchema()); + Filter reprojected = reprojectSpatialFilter(declaredCRS, source.getSchema(), original); + if(reprojected == original) { + return query; + } else { + Query rq = new Query(query); + rq.setFilter(reprojected); + return rq; + } } /** @@ -2377,12 +2416,35 @@ if(filter == null) { return rule; } + + // try to reproject the filter + Filter reprojected = reprojectSpatialFilter(declaredCRS, schema, filter); + if(reprojected == filter) { + return rule; + } + // clone the rule (the style can be reused over and over, we cannot alter it) and set the new filter + Rule rr = new RuleImpl(rule); + rr.setFilter(reprojected); + return rr; + } + + /** + * Reprojects spatial filters so that they match the feature source native CRS, and assuming all literal + * geometries are specified in the specified declaredCRS + */ + private Filter reprojectSpatialFilter(CoordinateReferenceSystem declaredCRS, + FeatureType schema, Filter filter) { + // NPE avoidance + if(filter == null) { + return null; + } + // do we have any spatial filter? SpatialFilterVisitor sfv = new SpatialFilterVisitor(); filter.accept(sfv, null); if(!sfv.hasSpatialFilter()) { - return rule; + return filter; } // all right, we need to default the literals to the declaredCRS and then reproject to @@ -2391,11 +2453,7 @@ Filter defaulted = (Filter) filter.accept(defaulter, null); ReprojectingFilterVisitor reprojector = new ReprojectingFilterVisitor(filterFactory, schema); Filter reprojected = (Filter) defaulted.accept(reprojector, null); - - // clone the rule (the style can be reused over and over, we cannot alter it) and set the new filter - Rule rr = new RuleImpl(rule); - rr.setFilter(reprojected); - return rr; + return reprojected; } /** Modified: trunk/modules/library/render/src/test/java/org/geotools/renderer/lite/SpatialFilterTest.java =================================================================== --- trunk/modules/library/render/src/test/java/org/geotools/renderer/lite/SpatialFilterTest.java 2012-05-27 09:12:50 UTC (rev 38763) +++ trunk/modules/library/render/src/test/java/org/geotools/renderer/lite/SpatialFilterTest.java 2012-05-27 09:20:15 UTC (rev 38764) @@ -7,6 +7,7 @@ import java.util.HashSet; import java.util.Set; +import org.geotools.data.DefaultQuery; import org.geotools.data.property.PropertyDataStore; import org.geotools.data.simple.SimpleFeatureSource; import org.geotools.factory.CommonFactoryFinder; @@ -22,7 +23,6 @@ import org.geotools.renderer.RenderListener; import org.geotools.styling.PolygonSymbolizer; import org.geotools.styling.Rule; -import org.geotools.styling.SLDTransformer; import org.geotools.styling.Style; import org.geotools.styling.StyleBuilder; import org.geotools.styling.Symbolizer; @@ -35,13 +35,14 @@ import org.opengis.referencing.crs.CRSAuthorityFactory; import org.opengis.referencing.crs.CoordinateReferenceSystem; +import com.vividsolutions.jts.geom.Envelope; import com.vividsolutions.jts.geom.Polygon; public class SpatialFilterTest { private static final long TIME = 2000; - FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2(); + FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2(null); SimpleFeatureSource squareFS; @@ -196,12 +197,9 @@ polygon.setUserData(utm31n); rule.setFilter(ff.intersects(ff.property("geom"), ff.literal(polygon))); - // force EPSG axis order interpretation - renderer.setRendererHints(Collections.singletonMap(StreamingRenderer.FORCE_EPSG_AXIS_ORDER_KEY, true)); - content.addLayer(new FeatureLayer(pointFS, style)); - RendererBaseTest.showRender("Spatial in EPSG order", renderer, TIME, bounds); + RendererBaseTest.showRender("Reprojected polygon", renderer, TIME, bounds); assertEquals(1, renderedIds.size()); assertEquals("point.4", renderedIds.iterator().next()); } @@ -211,17 +209,38 @@ // same as above, but with the style in SLD form Style style = RendererBaseTest.loadStyle(this, "spatialFilter.sld"); - // force EPSG axis order interpretation - renderer.setRendererHints(Collections.singletonMap(StreamingRenderer.FORCE_EPSG_AXIS_ORDER_KEY, true)); - content.addLayer(new FeatureLayer(pointFS, style)); - RendererBaseTest.showRender("Spatial in EPSG order", renderer, TIME, bounds); + RendererBaseTest.showRender("Reprojected polygon from SLD", renderer, TIME, bounds); assertEquals(1, renderedIds.size()); assertEquals("point.4", renderedIds.iterator().next()); } + @Test + public void testReprojectedPolygonFromDefinitionQuery() throws Exception { + // a spatial filter in a different SRS + CoordinateReferenceSystem utm31n = CRS.decode("EPSG:32631"); + CoordinateReferenceSystem wgs84 = CRS.decode("EPSG:4326"); + ReferencedEnvelope envWgs84 = new ReferencedEnvelope(1, 3, 5, 7, wgs84); + ReferencedEnvelope envUTM31N = envWgs84.transform(utm31n, true); + + // build the style + StyleBuilder sb = new StyleBuilder(); + Symbolizer ps = sb.createPointSymbolizer(); + Style style = sb.createStyle(ps); + + // build a filter for the layer own definition query + FeatureLayer layer = new FeatureLayer(pointFS, style); + Polygon polygon = JTS.toGeometry((Envelope) envUTM31N); + polygon.setUserData(utm31n); + layer.setQuery(new DefaultQuery(null, ff.intersects(ff.property("geom"), ff.literal(polygon)))); + + content.addLayer(layer); + + RendererBaseTest.showRender("Reprojected polygon as a definition query", renderer, TIME, bounds); + assertEquals(1, renderedIds.size()); + assertEquals("point.4", renderedIds.iterator().next()); + } - } |
From: <svn...@os...> - 2012-05-27 09:12:57
|
Author: aaime Date: 2012-05-27 02:12:50 -0700 (Sun, 27 May 2012) New Revision: 38763 Modified: branches/2.7.x/modules/library/render/src/main/java/org/geotools/renderer/lite/StreamingRenderer.java branches/2.7.x/modules/library/render/src/test/java/org/geotools/renderer/lite/SpatialFilterTest.java Log: GEOT-4155, applied also to layer definition queries Modified: branches/2.7.x/modules/library/render/src/main/java/org/geotools/renderer/lite/StreamingRenderer.java =================================================================== --- branches/2.7.x/modules/library/render/src/main/java/org/geotools/renderer/lite/StreamingRenderer.java 2012-05-27 09:12:32 UTC (rev 38762) +++ branches/2.7.x/modules/library/render/src/main/java/org/geotools/renderer/lite/StreamingRenderer.java 2012-05-27 09:12:50 UTC (rev 38763) @@ -121,6 +121,7 @@ import org.opengis.filter.expression.PropertyName; import org.opengis.parameter.GeneralParameterValue; import org.opengis.referencing.FactoryException; +import org.opengis.referencing.NoSuchAuthorityCodeException; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.operation.MathTransform; import org.opengis.referencing.operation.MathTransform2D; @@ -932,7 +933,7 @@ CoordinateReferenceSystem featCrs, Rectangle screenSize, GeometryDescriptor geometryAttribute, AffineTransform worldToScreenTransform) - throws IllegalFilterException, IOException { + throws IllegalFilterException, IOException, FactoryException { FeatureCollection<FeatureType, Feature> results = null; Query query = new Query(Query.ALL); Query definitionQuery; @@ -1025,7 +1026,7 @@ // sure to respect it by combining it with the bounding box one. // Currently this definition query is being set dynamically in geoserver // as per the user's filter, maxFeatures and startIndex WMS GetMap custom parameters - definitionQuery = currLayer.getQuery(); + definitionQuery = reprojectQuery(currLayer.getQuery(), source); if (definitionQuery != Query.ALL) { if (query == Query.ALL) { @@ -1099,7 +1100,6 @@ return source.getFeatures(query); } - /** * Takes care of eventual geometric transformations * @param styles @@ -2007,8 +2007,24 @@ * @throws FactoryException */ void reprojectSpatialFilters(final ArrayList<LiteFeatureTypeStyle> lfts, FeatureSource fs) throws FactoryException { + FeatureType schema = fs.getSchema(); + CoordinateReferenceSystem declaredCRS = getDeclaredSRS(schema); + + // reproject spatial filters in each fts + for (LiteFeatureTypeStyle fts : lfts) { + reprojectSpatialFilters(fts, declaredCRS, schema); + } + } + + /** + * Computes the declared SRS of a layer based on the layer schema and the EPSG forcing flag + * @param schema + * @return + * @throws FactoryException + * @throws NoSuchAuthorityCodeException + */ + private CoordinateReferenceSystem getDeclaredSRS(FeatureType schema) throws FactoryException { // compute the default SRS of the feature source - FeatureType schema = fs.getSchema(); CoordinateReferenceSystem declaredCRS = schema.getCoordinateReferenceSystem(); if(isEPSGAxisOrderForced()) { Integer code = CRS.lookupEpsgCode(declaredCRS, false); @@ -2016,11 +2032,34 @@ declaredCRS = CRS.decode("urn:ogc:def:crs:EPSG::" + code); } } - - // reproject spatial filters in each fts - for (LiteFeatureTypeStyle fts : lfts) { - reprojectSpatialFilters(fts, declaredCRS, schema); + return declaredCRS; + } + + /** + * Reprojects all spatial filters in the specified Query so that they match the native srs of the + * specified feature source + * + * @param query + * @param source + * @return + * @throws FactoryException + */ + private Query reprojectQuery(Query query, FeatureSource<FeatureType, Feature> source) throws FactoryException { + if(query == null || query.getFilter() == null) { + return query; } + + // compute the declared CRS + Filter original = query.getFilter(); + CoordinateReferenceSystem declaredCRS = getDeclaredSRS(source.getSchema()); + Filter reprojected = reprojectSpatialFilter(declaredCRS, source.getSchema(), original); + if(reprojected == original) { + return query; + } else { + Query rq = new Query(query); + rq.setFilter(reprojected); + return rq; + } } /** @@ -2048,12 +2087,35 @@ if(filter == null) { return rule; } + + // try to reproject the filter + Filter reprojected = reprojectSpatialFilter(declaredCRS, schema, filter); + if(reprojected == filter) { + return rule; + } + // clone the rule (the style can be reused over and over, we cannot alter it) and set the new filter + Rule rr = new RuleImpl(rule); + rr.setFilter(reprojected); + return rr; + } + + /** + * Reprojects spatial filters so that they match the feature source native CRS, and assuming all literal + * geometries are specified in the specified declaredCRS + */ + private Filter reprojectSpatialFilter(CoordinateReferenceSystem declaredCRS, + FeatureType schema, Filter filter) { + // NPE avoidance + if(filter == null) { + return null; + } + // do we have any spatial filter? SpatialFilterVisitor sfv = new SpatialFilterVisitor(); filter.accept(sfv, null); if(!sfv.hasSpatialFilter()) { - return rule; + return filter; } // all right, we need to default the literals to the declaredCRS and then reproject to @@ -2062,11 +2124,7 @@ Filter defaulted = (Filter) filter.accept(defaulter, null); ReprojectingFilterVisitor reprojector = new ReprojectingFilterVisitor(filterFactory, schema); Filter reprojected = (Filter) defaulted.accept(reprojector, null); - - // clone the rule (the style can be reused over and over, we cannot alter it) and set the new filter - Rule rr = new RuleImpl(rule); - rr.setFilter(reprojected); - return rr; + return reprojected; } /** Modified: branches/2.7.x/modules/library/render/src/test/java/org/geotools/renderer/lite/SpatialFilterTest.java =================================================================== --- branches/2.7.x/modules/library/render/src/test/java/org/geotools/renderer/lite/SpatialFilterTest.java 2012-05-27 09:12:32 UTC (rev 38762) +++ branches/2.7.x/modules/library/render/src/test/java/org/geotools/renderer/lite/SpatialFilterTest.java 2012-05-27 09:12:50 UTC (rev 38763) @@ -7,6 +7,7 @@ import java.util.HashSet; import java.util.Set; +import org.geotools.data.DefaultQuery; import org.geotools.data.property.PropertyDataStore; import org.geotools.data.simple.SimpleFeatureSource; import org.geotools.factory.CommonFactoryFinder; @@ -15,7 +16,6 @@ import org.geotools.geometry.jts.ReferencedEnvelope; import org.geotools.map.DefaultMapContext; import org.geotools.map.FeatureLayer; -import org.geotools.map.MapContent; import org.geotools.map.MapContext; import org.geotools.referencing.CRS; import org.geotools.referencing.CRS.AxisOrder; @@ -197,12 +197,9 @@ polygon.setUserData(utm31n); rule.setFilter(ff.intersects(ff.property("geom"), ff.literal(polygon))); - // force EPSG axis order interpretation - renderer.setRendererHints(Collections.singletonMap(StreamingRenderer.FORCE_EPSG_AXIS_ORDER_KEY, true)); - context.addLayer(new FeatureLayer(pointFS, style)); - RendererBaseTest.showRender("Spatial in EPSG order", renderer, TIME, bounds); + RendererBaseTest.showRender("Reprojected polygon", renderer, TIME, bounds); assertEquals(1, renderedIds.size()); assertEquals("point.4", renderedIds.iterator().next()); } @@ -212,17 +209,38 @@ // same as above, but with the style in SLD form Style style = RendererBaseTest.loadStyle(this, "spatialFilter.sld"); - // force EPSG axis order interpretation - renderer.setRendererHints(Collections.singletonMap(StreamingRenderer.FORCE_EPSG_AXIS_ORDER_KEY, true)); - context.addLayer(new FeatureLayer(pointFS, style)); - RendererBaseTest.showRender("Spatial in EPSG order", renderer, TIME, bounds); + RendererBaseTest.showRender("Reprojected polygon from SLD", renderer, TIME, bounds); assertEquals(1, renderedIds.size()); assertEquals("point.4", renderedIds.iterator().next()); } + @Test + public void testReprojectedPolygonFromDefinitionQuery() throws Exception { + // a spatial filter in a different SRS + CoordinateReferenceSystem utm31n = CRS.decode("EPSG:32631"); + CoordinateReferenceSystem wgs84 = CRS.decode("EPSG:4326"); + ReferencedEnvelope envWgs84 = new ReferencedEnvelope(1, 3, 5, 7, wgs84); + ReferencedEnvelope envUTM31N = envWgs84.transform(utm31n, true); + + // build the style + StyleBuilder sb = new StyleBuilder(); + Symbolizer ps = sb.createPointSymbolizer(); + Style style = sb.createStyle(ps); + + // build a filter for the layer own definition query + FeatureLayer layer = new FeatureLayer(pointFS, style); + Polygon polygon = JTS.toGeometry((Envelope) envUTM31N); + polygon.setUserData(utm31n); + layer.setQuery(new DefaultQuery(null, ff.intersects(ff.property("geom"), ff.literal(polygon)))); + + context.addLayer(layer); + + RendererBaseTest.showRender("Reprojected polygon as a definition query", renderer, TIME, bounds); + assertEquals(1, renderedIds.size()); + assertEquals("point.4", renderedIds.iterator().next()); + } - } |
Author: aaime Date: 2012-05-27 02:12:32 -0700 (Sun, 27 May 2012) New Revision: 38762 Added: branches/2.7.x/modules/library/main/src/main/java/org/geotools/filter/spatial/DefaultCRSFilterVisitor.java branches/2.7.x/modules/library/main/src/main/java/org/geotools/filter/spatial/ReprojectingFilterVisitor.java branches/2.7.x/modules/library/main/src/test/java/org/geotools/filter/spatial/ReprojectingFilterVisitorTest.java branches/2.7.x/modules/library/render/src/test/java/org/geotools/renderer/lite/SpatialFilterTest.java branches/2.7.x/modules/library/render/src/test/resources/org/geotools/renderer/lite/test-data/spatialFilter.sld Modified: branches/2.7.x/modules/library/render/src/main/java/org/geotools/renderer/lite/StreamingRenderer.java branches/2.7.x/modules/library/render/src/test/resources/org/geotools/renderer/lite/test-data/point.properties branches/2.7.x/modules/plugin/epsg-hsql/src/test/java/org/geotools/referencing/CRSTest.java Log: [GEOT-4155] Renderer does not handle spatial filters in projections others than the native data one Added: branches/2.7.x/modules/library/main/src/main/java/org/geotools/filter/spatial/DefaultCRSFilterVisitor.java =================================================================== --- branches/2.7.x/modules/library/main/src/main/java/org/geotools/filter/spatial/DefaultCRSFilterVisitor.java (rev 0) +++ branches/2.7.x/modules/library/main/src/main/java/org/geotools/filter/spatial/DefaultCRSFilterVisitor.java 2012-05-27 09:12:32 UTC (rev 38762) @@ -0,0 +1,82 @@ +/* + * GeoTools - The Open Source Java GIS Toolkit + * http://geotools.org + * + * (C) 2006-2008, Open Source Geospatial Foundation (OSGeo) + * + * 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; + * 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. + */ +package org.geotools.filter.spatial; + +import org.geotools.filter.visitor.DuplicatingFilterVisitor; +import org.geotools.referencing.CRS; +import org.opengis.filter.FilterFactory2; +import org.opengis.filter.expression.Literal; +import org.opengis.filter.spatial.BBOX; +import org.opengis.referencing.crs.CoordinateReferenceSystem; + +import com.vividsolutions.jts.geom.Geometry; + +/** + * Returns a clone of the provided filter where all geometries and bboxes that + * do not have a CRS gets the specified default one. + * + * @author Andrea Aime - The Open Planning Project + * + * + * @source $URL$ + */ +public class DefaultCRSFilterVisitor extends DuplicatingFilterVisitor { + private CoordinateReferenceSystem defaultCrs; + + public DefaultCRSFilterVisitor(FilterFactory2 factory, CoordinateReferenceSystem defaultCrs) { + super(factory); + this.defaultCrs = defaultCrs; + } + + public Object visit(BBOX filter, Object extraData) { + // if no srs is specified we can't transform anyways + String srs = filter.getSRS(); + if (srs != null && !"".equals(srs.trim())) + return super.visit(filter, extraData); + + try { + // grab the original envelope data + double minx = filter.getMinX(); + double miny = filter.getMinY(); + double maxx = filter.getMaxX(); + double maxy = filter.getMaxY(); + String propertyName = filter.getPropertyName(); + String defaultSrs = CRS.toSRS(defaultCrs); + + return getFactory(extraData).bbox(propertyName, minx, miny, maxx, maxy, defaultSrs); + } catch (Exception e) { + throw new RuntimeException("Could not decode srs '" + srs + "'", e); + } + } + + public Object visit(Literal expression, Object extraData) { + if (!(expression.getValue() instanceof Geometry)) + return super.visit(expression, extraData); + + // check if reprojection is needed + Geometry geom = (Geometry) expression.getValue(); + if(geom.getUserData() != null && geom.getUserData() instanceof CoordinateReferenceSystem) + return super.visit(expression, extraData); + + // clone the geometry and assign the new crs + Geometry clone = geom.getFactory().createGeometry(geom); + clone.setUserData(defaultCrs); + + // clone + return ff.literal(clone); + } +} \ No newline at end of file Added: branches/2.7.x/modules/library/main/src/main/java/org/geotools/filter/spatial/ReprojectingFilterVisitor.java =================================================================== --- branches/2.7.x/modules/library/main/src/main/java/org/geotools/filter/spatial/ReprojectingFilterVisitor.java (rev 0) +++ branches/2.7.x/modules/library/main/src/main/java/org/geotools/filter/spatial/ReprojectingFilterVisitor.java 2012-05-27 09:12:32 UTC (rev 38762) @@ -0,0 +1,512 @@ +/* + * GeoTools - The Open Source Java GIS Toolkit + * http://geotools.org + * + * (C) 2006-2008, Open Source Geospatial Foundation (OSGeo) + * + * 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; + * 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. + */ +package org.geotools.filter.spatial; + +import java.util.List; + +import org.geotools.filter.visitor.DuplicatingFilterVisitor; +import org.geotools.geometry.jts.JTS; +import org.geotools.geometry.jts.ReferencedEnvelope; +import org.geotools.referencing.CRS; +import org.opengis.feature.type.AttributeDescriptor; +import org.opengis.feature.type.FeatureType; +import org.opengis.feature.type.GeometryDescriptor; +import org.opengis.filter.BinaryComparisonOperator; +import org.opengis.filter.FilterFactory2; +import org.opengis.filter.PropertyIsEqualTo; +import org.opengis.filter.PropertyIsNotEqualTo; +import org.opengis.filter.capability.FunctionName; +import org.opengis.filter.expression.Expression; +import org.opengis.filter.expression.ExpressionVisitor; +import org.opengis.filter.expression.Function; +import org.opengis.filter.expression.Literal; +import org.opengis.filter.expression.PropertyName; +import org.opengis.filter.spatial.BBOX; +import org.opengis.filter.spatial.Beyond; +import org.opengis.filter.spatial.BinarySpatialOperator; +import org.opengis.filter.spatial.Contains; +import org.opengis.filter.spatial.Crosses; +import org.opengis.filter.spatial.DWithin; +import org.opengis.filter.spatial.Disjoint; +import org.opengis.filter.spatial.Equals; +import org.opengis.filter.spatial.Intersects; +import org.opengis.filter.spatial.Overlaps; +import org.opengis.filter.spatial.Touches; +import org.opengis.filter.spatial.Within; +import org.opengis.referencing.NoSuchAuthorityCodeException; +import org.opengis.referencing.crs.CoordinateReferenceSystem; + +import com.vividsolutions.jts.geom.Geometry; + +/** + * Returns a clone of the provided filter where all geometries and bboxes have + * been reprojected to the CRS of the associated attributes. The working + * assumption is that the filters specified are strictly compliant with the OGC + * spec, so the first item is always a {@link PropertyName}, and the second + * always a {@link Literal} + * + * @author Andrea Aime - The Open Planning Project + * + * + * @source $URL$ + */ +public class ReprojectingFilterVisitor extends DuplicatingFilterVisitor { + FeatureType featureType; + + public ReprojectingFilterVisitor(FilterFactory2 factory, FeatureType featureType) { + super(factory); + this.featureType = featureType; + } + + /** + * Returns the CRS associated to a property in the feature type. May be null + * if the property is not geometric, or if the CRS is not set + * + * @param propertyName + * @return + */ + private CoordinateReferenceSystem findPropertyCRS(PropertyName propertyName) { + AttributeDescriptor at = (AttributeDescriptor) propertyName.evaluate(featureType); + if (at instanceof GeometryDescriptor) { + GeometryDescriptor gat = (GeometryDescriptor) at; + return gat.getCoordinateReferenceSystem(); + } else { + return null; + } + } + + public Object visit(BBOX filter, Object extraData) { + // if no srs is specified we can't transform anyways + String srs = filter.getSRS(); + if (srs == null || "".equals(srs.trim())) + return super.visit(filter, extraData); + + try { + // grab the original envelope data + double minx = filter.getMinX(); + double miny = filter.getMinY(); + double maxx = filter.getMaxX(); + double maxy = filter.getMaxY(); + // parse the srs, it might be a code or a WKT definition + CoordinateReferenceSystem crs; + try { + crs = CRS.decode(srs); + } catch (NoSuchAuthorityCodeException e) { + crs = CRS.parseWKT(srs); + } + + // grab the property data + String propertyName = filter.getPropertyName(); + CoordinateReferenceSystem targetCrs = findPropertyCRS(ff.property(propertyName)); + + // if there is a mismatch, reproject and replace + if (crs != null && targetCrs != null && !CRS.equalsIgnoreMetadata(crs, targetCrs)) { + ReferencedEnvelope envelope = new ReferencedEnvelope(minx, maxx, miny, maxy, crs); + envelope = envelope.transform(targetCrs, true); + minx = envelope.getMinX(); + miny = envelope.getMinY(); + maxx = envelope.getMaxX(); + maxy = envelope.getMaxY(); + + // set the srs. If we have a code we use it, otherwise we use a WKT definition + if (targetCrs.getIdentifiers().isEmpty()) { + // fall back to WKT + srs = targetCrs.toString(); + } else { + srs = targetCrs.getIdentifiers().iterator().next().toString(); + } + } + + return getFactory(extraData).bbox(propertyName, minx, miny, maxx, maxy, srs); + } catch (Exception e) { + throw new RuntimeException("Could not decode srs '" + srs + "'", e); + } + + } + + public Object visit(PropertyIsEqualTo filter, Object extraData) { + return new BinaryComparisonTransformer() { + + Object cloneFilter(BinaryComparisonOperator filter, Object extraData) { + return ReprojectingFilterVisitor.super.visit((PropertyIsEqualTo) filter, extraData); + } + + Object cloneFilter(BinaryComparisonOperator bso, Object extraData, Expression ex1, + Expression ex2) { + return ff.equal(ex1, ex2, bso.isMatchingCase()); + } + }.transform(filter, extraData); + } + + public Object visit(PropertyIsNotEqualTo filter, Object extraData) { + return new BinaryComparisonTransformer() { + + Object cloneFilter(BinaryComparisonOperator filter, Object extraData) { + return ReprojectingFilterVisitor.super.visit((PropertyIsNotEqualTo) filter, extraData); + } + + Object cloneFilter(BinaryComparisonOperator bso, Object extraData, Expression ex1, + Expression ex2) { + return ff.notEqual(ex1, ex2, bso.isMatchingCase()); + } + }.transform(filter, extraData); + } + + public Object visit(Beyond filter, Object extraData) { + return new GeometryFilterTransformer() { + + Object cloneFilter(BinarySpatialOperator filter, Object extraData) { + return ReprojectingFilterVisitor.super.visit((Beyond) filter, extraData); + } + + Object cloneFilter(BinarySpatialOperator bso, Object extraData, Expression ex1, + Expression ex2) { + Beyond filter = (Beyond) bso; + return ff.beyond(ex1, ex2, filter.getDistance(), filter.getDistanceUnits()); + } + }.transform(filter, extraData); + } + + public Object visit(Contains filter, Object extraData) { + return new GeometryFilterTransformer() { + + Object cloneFilter(BinarySpatialOperator filter, Object extraData) { + return ReprojectingFilterVisitor.super.visit((Contains) filter, extraData); + } + + Object cloneFilter(BinarySpatialOperator bso, Object extraData, Expression ex1, + Expression ex2) { + return ff.contains(ex1, ex2); + } + }.transform(filter, extraData); + } + + public Object visit(Crosses filter, Object extraData) { + return new GeometryFilterTransformer() { + + Object cloneFilter(BinarySpatialOperator filter, Object extraData) { + return ReprojectingFilterVisitor.super.visit((Crosses) filter, extraData); + } + + Object cloneFilter(BinarySpatialOperator bso, Object extraData, Expression ex1, + Expression ex2) { + return ff.crosses(ex1, ex2); + } + }.transform(filter, extraData); + } + + public Object visit(Disjoint filter, Object extraData) { + return new GeometryFilterTransformer() { + + Object cloneFilter(BinarySpatialOperator filter, Object extraData) { + return ReprojectingFilterVisitor.super.visit((Disjoint) filter, extraData); + } + + Object cloneFilter(BinarySpatialOperator bso, Object extraData, Expression ex1, + Expression ex2) { + return ff.disjoint(ex1, ex2); + } + }.transform(filter, extraData); + } + + public Object visit(DWithin filter, Object extraData) { + return new GeometryFilterTransformer() { + + Object cloneFilter(BinarySpatialOperator filter, Object extraData) { + return ReprojectingFilterVisitor.super.visit((DWithin) filter, extraData); + } + + Object cloneFilter(BinarySpatialOperator bso, Object extraData, Expression ex1, + Expression ex2) { + DWithin filter = (DWithin) bso; + return ff.dwithin(ex1, ex2, filter.getDistance(), filter.getDistanceUnits()); + } + }.transform(filter, extraData); + } + + public Object visit(Intersects filter, Object extraData) { + return new GeometryFilterTransformer() { + + Object cloneFilter(BinarySpatialOperator filter, Object extraData) { + return ReprojectingFilterVisitor.super.visit((Intersects) filter, extraData); + } + + Object cloneFilter(BinarySpatialOperator bso, Object extraData, Expression ex1, + Expression ex2) { + return ff.intersects(ex1, ex2); + } + }.transform(filter, extraData); + } + + public Object visit(Overlaps filter, Object extraData) { + return new GeometryFilterTransformer() { + + Object cloneFilter(BinarySpatialOperator filter, Object extraData) { + return ReprojectingFilterVisitor.super.visit((Overlaps) filter, extraData); + } + + Object cloneFilter(BinarySpatialOperator bso, Object extraData, Expression ex1, + Expression ex2) { + return ff.overlaps(ex1, ex2); + } + }.transform(filter, extraData); + } + + public Object visit(Touches filter, Object extraData) { + return new GeometryFilterTransformer() { + + Object cloneFilter(BinarySpatialOperator filter, Object extraData) { + return ReprojectingFilterVisitor.super.visit((Touches) filter, extraData); + } + + Object cloneFilter(BinarySpatialOperator bso, Object extraData, Expression ex1, + Expression ex2) { + return ff.touches(ex1, ex2); + } + }.transform(filter, extraData); + } + + public Object visit(Within filter, Object extraData) { + return new GeometryFilterTransformer() { + + Object cloneFilter(BinarySpatialOperator filter, Object extraData) { + return ReprojectingFilterVisitor.super.visit((Within) filter, extraData); + } + + Object cloneFilter(BinarySpatialOperator bso, Object extraData, Expression ex1, + Expression ex2) { + return ff.within(ex1, ex2); + } + }.transform(filter, extraData); + } + + public Object visit(Equals filter, Object extraData) { + return new GeometryFilterTransformer() { + + Object cloneFilter(BinarySpatialOperator filter, Object extraData) { + return ReprojectingFilterVisitor.super.visit((Equals) filter, extraData); + } + + Object cloneFilter(BinarySpatialOperator bso, Object extraData, Expression ex1, + Expression ex2) { + return ff.equal(ex1, ex2); + } + }.transform(filter, extraData); + } + + /** + * Helper method to reproject a geometry. + */ + protected Geometry reproject( Object value, CoordinateReferenceSystem propertyCrs) { + if ( value == null ) { + return null; + } + + if (!(value instanceof Geometry)) + throw new IllegalArgumentException("Binary geometry filter, but second expression " + + "is not a geometry literal? (it's a " + value.getClass() + ")"); + Geometry geom = (Geometry) value; + + // does it make sense to proceed? + if (geom.getUserData() == null + || !(geom.getUserData() instanceof CoordinateReferenceSystem)) + return geom; + + try { + // reproject + CoordinateReferenceSystem geomCRS = (CoordinateReferenceSystem) geom.getUserData(); + Geometry transformed = JTS.transform(geom, CRS.findMathTransform(geomCRS, propertyCrs, true)); + transformed.setUserData(propertyCrs); + + return transformed; + } catch(Exception e) { + throw new RuntimeException("Could not reproject geometry " + value, e); + } + } + + Expression reproject(final Expression expression, + final CoordinateReferenceSystem propertyCrs, boolean forceReprojection) { + // check for case of section filter being a function + if (expression instanceof Function) { + //wrap the function in one that will transform the result + final Function delegate = (Function) expression; + return new FunctionReprojector(propertyCrs, delegate); + } else if (expression instanceof Literal) { + // second expression is a geometry literal + Object value = ((Literal) expression).getValue(); + return ff.literal(reproject(value,propertyCrs)); + } else if(forceReprojection) { + throw new IllegalArgumentException("Binary geometry filter, but second expression " + + "is not a literal or function? (it's a " + expression.getClass() + ")"); + } else { + // we were not forced to reproject, then return the original expression + return null; + } + } + + /** + * Factors out most of the logic needed to reproject a geometry filter, leaving subclasses + * only the need to call the appropriate methods to create the new binary spatial filter + * @author Andrea Aime - The Open Plannig Project + * + */ + private abstract class GeometryFilterTransformer { + Object transform(final BinarySpatialOperator filter, Object extraData) { + // check working assumptions, first expression is a property + if (!(filter.getExpression1() instanceof PropertyName)) + throw new IllegalArgumentException("Binary geometry filter, but first expression " + + "is not a property name? (it's a " + filter.getExpression1().getClass() + + ")"); + final CoordinateReferenceSystem propertyCrs = findPropertyCRS((PropertyName) filter.getExpression1()); + + if (propertyCrs == null) + return cloneFilter(filter, extraData); + + // "transformed" expressions + Expression ex1 = (Expression) filter.getExpression1().accept( + ReprojectingFilterVisitor.this, extraData); + Expression ex2 = reproject(filter.getExpression2(), propertyCrs, true); + + return cloneFilter(filter, extraData, ex1, ex2 ); + } + + /** + * Straight cloning using cascaded visit + * + * @param filter + * @param extraData + * @return + */ + abstract Object cloneFilter(BinarySpatialOperator filter, Object extraData); + + /** + * Clone with the provided parameters as first and second expressions + * + * @param filter + * @param extraData + * @param ex1 + * @param ex2 + * @return + */ + abstract Object cloneFilter(BinarySpatialOperator filter, Object extraData, Expression ex1, + Expression ex2); + } + + /** + * Factors out most of the logic needed to reproject a binary comparison filter, leaving subclasses + * only the need to call the appropriate methods to create the new binary spatial filter + * @author Andrea Aime - The Open Plannig Project + * + */ + private abstract class BinaryComparisonTransformer { + Object transform(BinaryComparisonOperator filter, Object extraData) { + // binary filters may use two random expressions, check if we have + // enough information for a reprojection + PropertyName name; + Expression other; + if ((filter.getExpression1() instanceof PropertyName)) { + name = (PropertyName) filter.getExpression1(); + other = filter.getExpression2(); + } else if(filter.getExpression2() instanceof PropertyName) { + name = (PropertyName) filter.getExpression2(); + other = filter.getExpression1(); + } else { + return cloneFilter(filter, extraData); + } + + CoordinateReferenceSystem propertyCrs = findPropertyCRS(name); + + // we have to reproject only if the property is geometric + if (propertyCrs == null) + return cloneFilter(filter, extraData); + + // "transformed" expressions + Expression ex1 = (Expression) name.accept(ReprojectingFilterVisitor.this, extraData); + Expression ex2 = reproject(other, propertyCrs, false); + if(ex2 == null) + ex2 = (Expression) other.accept(ReprojectingFilterVisitor.this, extraData); + + return cloneFilter(filter, extraData, ex1, ex2 ); + } + + /** + * Straight cloning using cascaded visit + * + * @param filter + * @param extraData + * @return + */ + abstract Object cloneFilter(BinaryComparisonOperator filter, Object extraData); + + /** + * Clone with the provided parameters as first and second expressions + * + * @param filter + * @param extraData + * @param ex1 + * @param ex2 + * @return + */ + abstract Object cloneFilter(BinaryComparisonOperator filter, Object extraData, Expression ex1, + Expression ex2); + + } + + /** + * Makes sure that the result of a function gets reprojected to the specified CRS, should + * it be a Geometry + * @author Justin DeOliveira - TOPP + * + */ + protected class FunctionReprojector implements Function { + private final CoordinateReferenceSystem propertyCrs; + + private final Function delegate; + + protected FunctionReprojector(CoordinateReferenceSystem propertyCrs, Function delegate) { + this.propertyCrs = propertyCrs; + this.delegate = delegate; + } + + public String getName() { + return delegate.getName(); + } + + public List<Expression> getParameters() { + return delegate.getParameters(); + } + + public Object accept(ExpressionVisitor visitor, Object extraData) { + return delegate.accept( visitor, extraData ); + } + + public Object evaluate(Object object) { + Object value = delegate.evaluate( object ); + return reproject(value, propertyCrs); + } + + public <T> T evaluate(Object object, Class<T> context) { + T value = delegate.evaluate( object, context ); + return (T) reproject(value, propertyCrs); + } + + public Literal getFallbackValue() { + return null; + } + } + +} Added: branches/2.7.x/modules/library/main/src/test/java/org/geotools/filter/spatial/ReprojectingFilterVisitorTest.java =================================================================== --- branches/2.7.x/modules/library/main/src/test/java/org/geotools/filter/spatial/ReprojectingFilterVisitorTest.java (rev 0) +++ branches/2.7.x/modules/library/main/src/test/java/org/geotools/filter/spatial/ReprojectingFilterVisitorTest.java 2012-05-27 09:12:32 UTC (rev 38762) @@ -0,0 +1,258 @@ +package org.geotools.filter.spatial; + +import java.util.Collections; +import java.util.List; + +import junit.framework.TestCase; + +import org.geotools.data.DataUtilities; +import org.geotools.factory.CommonFactoryFinder; +import org.geotools.factory.GeoTools; +import org.geotools.factory.Hints; +import org.geotools.feature.FeatureTypes; +import org.geotools.filter.capability.FunctionNameImpl; +import org.geotools.filter.spatial.ReprojectingFilterVisitor; +import org.geotools.referencing.CRS; +import org.opengis.feature.simple.SimpleFeatureType; +import org.opengis.filter.Filter; +import org.opengis.filter.FilterFactory2; +import org.opengis.filter.PropertyIsEqualTo; +import org.opengis.filter.capability.FunctionName; +import org.opengis.filter.expression.Expression; +import org.opengis.filter.expression.ExpressionVisitor; +import org.opengis.filter.expression.Function; +import org.opengis.filter.expression.Literal; +import org.opengis.filter.spatial.BBOX; +import org.opengis.filter.spatial.Intersects; +import org.opengis.referencing.crs.CoordinateReferenceSystem; + +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.GeometryFactory; +import com.vividsolutions.jts.geom.LineString; + +/** + * + * + * @source $URL$ + */ +public class ReprojectingFilterVisitorTest extends TestCase { + + SimpleFeatureType ft; + FilterFactory2 ff; + ReprojectingFilterVisitor reprojector; + + protected void setUp() throws Exception { + // this is the only thing that actually forces CRS object to give up + // its configuration, necessary when tests are run by Maven, one JVM for all + // the tests in this module + Hints.putSystemDefault(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.TRUE); + GeoTools.fireConfigurationChanged(); + ft = DataUtilities.createType("testType", "geom:Point:srid=4326,line:LineString,name:String,id:int"); + ff = CommonFactoryFinder.getFilterFactory2(GeoTools.getDefaultHints()); + reprojector = new ReprojectingFilterVisitor(ff, ft); + } + + + /** + * Make sure it does not break with non spatial filters + */ + public void testNoProjection() { + Filter idFilter = ff.id(Collections.singleton(ff.featureId("testType:1"))); + Filter clone = (Filter) idFilter.accept(reprojector, null); + assertNotSame(idFilter, clone); + assertEquals(idFilter, clone); + } + + public void testBboxNoReprojection() { + // no reprojection needed in fact + Filter bbox = ff.bbox(ff.property("geom"), 10, 10, 20, 20, "EPSG:4326"); + Filter clone = (Filter) bbox.accept(reprojector, null); + assertNotSame(bbox, clone); + assertEquals(bbox, clone); + } + + public void testBboxReproject() { + // see if coordinates gets flipped, urn forces lat/lon interpretation + BBOX bbox = ff.bbox(ff.property("geom"), 10, 15, 20, 25, "urn:x-ogc:def:crs:EPSG:6.11.2:4326"); + Filter clone = (Filter) bbox.accept(reprojector, null); + assertNotSame(bbox, clone); + BBOX clonedBbox = (BBOX) clone; + assertEquals(bbox.getPropertyName(), clonedBbox.getPropertyName()); + assertEquals(15, clonedBbox.getMinX(), 1e-6); + assertEquals(10, clonedBbox.getMinY(), 1e-6); + assertEquals(25, clonedBbox.getMaxX(), 1e-6); + assertEquals(20, clonedBbox.getMaxY(), 1e-6); + assertEquals("EPSG:4326", clonedBbox.getSRS()); + } + + public void testBboxReprojectNoNativeAuthority() throws Exception { + // like WGS84, but no authority + String wkt = "GEOGCS[\"WGS 84\", DATUM[\"World Geodetic System 1984\", SPHEROID[\"WGS 84\", 6378137.0, 298.257223563]], PRIMEM[\"Greenwich\", 0.0], UNIT[\"degree\", 0.017453292519943295], AXIS[\"Geodetic longitude\", EAST], AXIS[\"Geodetic latitude\", NORTH]]"; + CoordinateReferenceSystem crs = CRS.parseWKT(wkt); + SimpleFeatureType newFt = FeatureTypes.transform(ft, crs); + reprojector = new ReprojectingFilterVisitor(ff, newFt); + + BBOX bbox = ff.bbox(ff.property("geom"), 10, 15, 20, 25, "urn:x-ogc:def:crs:EPSG:6.11.2:4326"); + Filter clone = (Filter) bbox.accept(reprojector, null); + assertNotSame(bbox, clone); + BBOX clonedBbox = (BBOX) clone; + assertEquals(bbox.getPropertyName(), clonedBbox.getPropertyName()); + assertTrue(15 == clonedBbox.getMinX()); + assertTrue(10 == clonedBbox.getMinY()); + assertTrue(25 == clonedBbox.getMaxX()); + assertTrue(20 == clonedBbox.getMaxY()); + // the srs code cannot be found, but it's legal to use a WKT description instead +// CoordinateReferenceSystem reprojected = CRS.parseWKT(clonedBbox.getSRS()); +// assertTrue(CRS.equalsIgnoreMetadata(crs, reprojected)); + } + + public void testBboxReprojectUnreferencedProperty() { + // see if coordinates gets flipped, urn forces lat/lon interpretation + BBOX bbox = ff.bbox(ff.property("line"), 10, 15, 20, 25, "urn:x-ogc:def:crs:EPSG:6.11.2:4326"); + Filter clone = (Filter) bbox.accept(reprojector, null); + assertNotSame(bbox, clone); + assertEquals(bbox, clone); + } + + public void testBboxReprojectUnreferencedBBox() { + // see if coordinates gets flipped, urn forces lat/lon interpretation + BBOX bbox = ff.bbox(ff.property("geom"), 10, 15, 20, 25, null); + Filter clone = (Filter) bbox.accept(reprojector, null); + assertNotSame(bbox, clone); + assertEquals(bbox, clone); + } + + public void testIntersectsReproject() throws Exception { + GeometryFactory gf = new GeometryFactory(); + LineString ls = gf.createLineString(new Coordinate[] {new Coordinate(10, 15), new Coordinate(20, 25)}); + ls.setUserData(CRS.decode("urn:x-ogc:def:crs:EPSG:6.11.2:4326")); + + // see if coordinates gets flipped, urn forces lat/lon interpretation + Intersects original = ff.intersects(ff.property("geom"), ff.literal(ls)); + Filter clone = (Filter) original.accept(reprojector, null); + assertNotSame(original, clone); + Intersects isClone = (Intersects) clone; + assertEquals(isClone.getExpression1(), original.getExpression1()); + LineString clonedLs = (LineString) ((Literal) isClone.getExpression2()).getValue(); + assertTrue(15 == clonedLs.getCoordinateN(0).x); + assertTrue(10 == clonedLs.getCoordinateN(0).y); + assertTrue(25 == clonedLs.getCoordinateN(1).x); + assertTrue(20 == clonedLs.getCoordinateN(1).y); + assertEquals(CRS.decode("EPSG:4326"), clonedLs.getUserData()); + } + + public void testIntersectsUnreferencedGeometry() throws Exception { + GeometryFactory gf = new GeometryFactory(); + LineString ls = gf.createLineString(new Coordinate[] {new Coordinate(10, 15), new Coordinate(20, 25)}); + + // see if coordinates gets flipped, urn forces lat/lon interpretation + Intersects original = ff.intersects(ff.property("geom"), ff.literal(ls)); + Filter clone = (Filter) original.accept(reprojector, null); + assertNotSame(original, clone); + assertEquals(original, clone); + } + + public void testIntersectsUnreferencedProperty() throws Exception { + GeometryFactory gf = new GeometryFactory(); + LineString ls = gf.createLineString(new Coordinate[] {new Coordinate(10, 15), new Coordinate(20, 25)}); + ls.setUserData(CRS.decode("urn:x-ogc:def:crs:EPSG:6.11.2:4326")); + + // see if coordinates gets flipped, urn forces lat/lon interpretation + Intersects original = ff.intersects(ff.property("line"), ff.literal(ls)); + Filter clone = (Filter) original.accept(reprojector, null); + assertNotSame(original, clone); + assertEquals(original, clone); + } + + public void testPropertyEqualsFirstArgumentNotPropertyName() throws Exception { + GeometryFactory gf = new GeometryFactory(); + LineString ls = gf.createLineString(new Coordinate[] {new Coordinate(10, 15), new Coordinate(20, 25)}); + ls.setUserData(CRS.decode("urn:x-ogc:def:crs:EPSG:6.11.2:4326")); + + // make sure a class cast does not occur, see: http://jira.codehaus.org/browse/GEOS-1860 + Function function = ff.function("geometryType", ff.property("geom")); + PropertyIsEqualTo original = ff.equals(ff.literal("Point"), function); + Filter clone = (Filter) original.accept(reprojector, null); + assertNotSame(original, clone); + assertEquals(original, clone); + + // try the opposite, literal and function + original = ff.equals(function, ff.literal("Point")); + clone = (Filter) original.accept(reprojector, null); + assertNotSame(original, clone); + assertEquals(original, clone); + } + + public void testIntersectsWithFunction() throws Exception { + Function function = new GeometryFunction(); + + // see if coordinates gets flipped, urn forces lat/lon interpretation + Intersects original = ff.intersects(ff.property("geom"), function); + Filter clone = (Filter) original.accept(reprojector, null); + assertNotSame(original, clone); + Intersects isClone = (Intersects) clone; + assertEquals(isClone.getExpression1(), original.getExpression1()); + LineString clonedLs = (LineString) isClone.getExpression2().evaluate(null); + assertTrue(15 == clonedLs.getCoordinateN(0).x); + assertTrue(10 == clonedLs.getCoordinateN(0).y); + assertTrue(25 == clonedLs.getCoordinateN(1).x); + assertTrue(20 == clonedLs.getCoordinateN(1).y); + assertEquals(CRS.decode("EPSG:4326"), clonedLs.getUserData()); + } + + public void testPropertyEqualWithFunction() throws Exception { + Function function = new GeometryFunction(); + + // see if coordinates gets flipped, urn forces lat/lon interpretation + PropertyIsEqualTo original = ff.equals(ff.property("geom"), function); + PropertyIsEqualTo clone = (PropertyIsEqualTo) original.accept(reprojector, null); + assertNotSame(original, clone); + assertEquals(clone.getExpression1(), original.getExpression1()); + LineString clonedLs = (LineString) clone.getExpression2().evaluate(null); + assertTrue(15 == clonedLs.getCoordinateN(0).x); + assertTrue(10 == clonedLs.getCoordinateN(0).y); + assertTrue(25 == clonedLs.getCoordinateN(1).x); + assertTrue(20 == clonedLs.getCoordinateN(1).y); + assertEquals(CRS.decode("EPSG:4326"), clonedLs.getUserData()); + } + + + + + + + private final class GeometryFunction implements Function { + final LineString ls; + + + public GeometryFunction() throws Exception { + GeometryFactory gf = new GeometryFactory(); + ls = gf.createLineString(new Coordinate[] {new Coordinate(10, 15), new Coordinate(20, 25)}); + ls.setUserData(CRS.decode("urn:x-ogc:def:crs:EPSG:6.11.2:4326")); + } + + public String getName() { + return "function"; + } + + public List<Expression> getParameters() { + return Collections.EMPTY_LIST; + } + + public Object accept(ExpressionVisitor visitor, Object extraData) { + return visitor.visit( this, extraData ); + } + + public Object evaluate(Object object) { + return ls; + } + + public <T> T evaluate(Object object, Class<T> context) { + return (T) ls; + } + + public Literal getFallbackValue() { + return null; + } + } +} \ No newline at end of file Modified: branches/2.7.x/modules/library/render/src/main/java/org/geotools/renderer/lite/StreamingRenderer.java =================================================================== --- branches/2.7.x/modules/library/render/src/main/java/org/geotools/renderer/lite/StreamingRenderer.java 2012-05-27 09:11:50 UTC (rev 38761) +++ branches/2.7.x/modules/library/render/src/main/java/org/geotools/renderer/lite/StreamingRenderer.java 2012-05-27 09:12:32 UTC (rev 38762) @@ -68,7 +68,10 @@ import org.geotools.feature.FeatureTypes; import org.geotools.filter.IllegalFilterException; import org.geotools.filter.function.GeometryTransformationVisitor; +import org.geotools.filter.spatial.DefaultCRSFilterVisitor; +import org.geotools.filter.spatial.ReprojectingFilterVisitor; import org.geotools.filter.visitor.SimplifyingFilterVisitor; +import org.geotools.filter.visitor.SpatialFilterVisitor; import org.geotools.geometry.jts.Decimator; import org.geotools.geometry.jts.GeometryClipper; import org.geotools.geometry.jts.LiteCoordinateSequence; @@ -97,6 +100,7 @@ import org.geotools.styling.PointSymbolizer; import org.geotools.styling.RasterSymbolizer; import org.geotools.styling.Rule; +import org.geotools.styling.RuleImpl; import org.geotools.styling.StyleAttributeExtractor; import org.geotools.styling.Symbolizer; import org.geotools.styling.TextSymbolizer; @@ -112,7 +116,7 @@ import org.opengis.feature.type.GeometryDescriptor; import org.opengis.feature.type.PropertyDescriptor; import org.opengis.filter.Filter; -import org.opengis.filter.FilterFactory; +import org.opengis.filter.FilterFactory2; import org.opengis.filter.expression.Expression; import org.opengis.filter.expression.PropertyName; import org.opengis.parameter.GeneralParameterValue; @@ -187,7 +191,7 @@ int error = 0; /** Filter factory for creating bounding box filters */ - private final static FilterFactory filterFactory = CommonFactoryFinder.getFilterFactory(null); + private final static FilterFactory2 filterFactory = CommonFactoryFinder.getFilterFactory2(null); private final static PropertyName gridPropertyName = filterFactory.property("grid"); @@ -343,6 +347,7 @@ private static boolean VECTOR_RENDERING_ENABLED_DEFAULT = false; public static final String LABEL_CACHE_KEY = "labelCache"; + public static final String FORCE_EPSG_AXIS_ORDER_KEY = "ForceEPSGAxisOrder"; public static final String DPI_KEY = "dpi"; public static final String DECLARED_SCALE_DENOM_KEY = "declaredScaleDenominator"; public static final String OPTIMIZED_DATA_LOADING_KEY = "optimizedDataLoadingEnabled"; @@ -357,7 +362,10 @@ * and the displayed area of the map. * "dpi" - Integer number of dots per inch of the display 90 DPI is the default (as declared by OGC) * "forceCRS" - CoordinateReferenceSystem declares to the renderer that all layers are of the CRS declared in this hint - * "labelCache" - Declares the label cache that will be used by the renderer. + * "labelCache" - Declares the label cache that will be used by the renderer. + * "forceEPSGAxisOrder" - When doing spatial filter reprojection (from the SLD towards the native CRS) assume the geometries + * are expressed with the axis order suggested by the official EPSG database, regardless of how the + * CRS system might be configured */ private Map rendererHints = null; @@ -1328,7 +1336,23 @@ return false; return Boolean.TRUE.equals(result); } + + /** + * Checks if the geometries in spatial filters in the SLD must be assumed to be expressed + * in the official EPSG axis order, regardless of how the referencing subsystem is configured + * (this is required to support filter reprojection in WMS 1.3+) + * @return + */ + private boolean isEPSGAxisOrderForced() { + if (rendererHints == null) + return false; + Object result = rendererHints.get(FORCE_EPSG_AXIS_ORDER_KEY); + if (result == null) + return false; + return Boolean.TRUE.equals(result); + } + /** * Checks if vector rendering is enabled or not. * See {@link SLDStyleFactory#isVectorRenderingEnabled()} for a full explanation. @@ -1866,7 +1890,7 @@ final private void processStylers(final Graphics2D graphics, MapLayer currLayer, AffineTransform at, CoordinateReferenceSystem destinationCrs, Envelope mapArea, - Rectangle screenSize, String layerId) throws IllegalFilterException, IOException { + Rectangle screenSize, String layerId) throws IllegalFilterException, IOException, FactoryException { /* * DJB: changed this a wee bit so that it now does the layer query AFTER @@ -1906,6 +1930,10 @@ if(lfts.size() == 0) return; + // make sure all spatial filters in the feature source native SRS + reprojectSpatialFilters(lfts, featureSource); + + // apply the uom and dpi rescale applyUnitRescale(lfts); LiteFeatureTypeStyle[] featureTypeStyleArray = (LiteFeatureTypeStyle[]) lfts.toArray(new LiteFeatureTypeStyle[lfts.size()]); @@ -1972,6 +2000,76 @@ } /** + * Reprojects the spatial filters in each {@link LiteFeatureTypeStyle} so that they match + * the feature source native coordinate system + * @param lfts + * @param fs + * @throws FactoryException + */ + void reprojectSpatialFilters(final ArrayList<LiteFeatureTypeStyle> lfts, FeatureSource fs) throws FactoryException { + // compute the default SRS of the feature source + FeatureType schema = fs.getSchema(); + CoordinateReferenceSystem declaredCRS = schema.getCoordinateReferenceSystem(); + if(isEPSGAxisOrderForced()) { + Integer code = CRS.lookupEpsgCode(declaredCRS, false); + if(code != null) { + declaredCRS = CRS.decode("urn:ogc:def:crs:EPSG::" + code); + } + } + + // reproject spatial filters in each fts + for (LiteFeatureTypeStyle fts : lfts) { + reprojectSpatialFilters(fts, declaredCRS, schema); + } + } + + /** + * Reprojects spatial filters so that they match the feature source native CRS, and assuming all literal + * geometries are specified in the specified declaredCRS + */ + void reprojectSpatialFilters(LiteFeatureTypeStyle fts, CoordinateReferenceSystem declaredCRS, FeatureType schema) { + for (int i = 0; i < fts.ruleList.length; i++) { + fts.ruleList[i] = reprojectSpatialFilters(fts.ruleList[i], declaredCRS, schema); + } + if(fts.elseRules != null) { + for (int i = 0; i < fts.elseRules.length; i++) { + fts.elseRules[i] = reprojectSpatialFilters(fts.elseRules[i], declaredCRS, schema); + } + } + } + + /** + * Reprojects spatial filters so that they match the feature source native CRS, and assuming all literal + * geometries are specified in the specified declaredCRS + */ + private Rule reprojectSpatialFilters(Rule rule, CoordinateReferenceSystem declaredCRS, FeatureType schema) { + // NPE avoidance + Filter filter = rule.getFilter(); + if(filter == null) { + return rule; + } + + // do we have any spatial filter? + SpatialFilterVisitor sfv = new SpatialFilterVisitor(); + filter.accept(sfv, null); + if(!sfv.hasSpatialFilter()) { + return rule; + } + + // all right, we need to default the literals to the declaredCRS and then reproject to + // the native one + DefaultCRSFilterVisitor defaulter = new DefaultCRSFilterVisitor(filterFactory, declaredCRS); + Filter defaulted = (Filter) filter.accept(defaulter, null); + ReprojectingFilterVisitor reprojector = new ReprojectingFilterVisitor(filterFactory, schema); + Filter reprojected = (Filter) defaulted.accept(reprojector, null); + + // clone the rule (the style can be reused over and over, we cannot alter it) and set the new filter + Rule rr = new RuleImpl(rule); + rr.setFilter(reprojected); + return rr; + } + + /** * Utility method to apply the two rescale visitors without duplicating code * @param fts * @param visitor Added: branches/2.7.x/modules/library/render/src/test/java/org/geotools/renderer/lite/SpatialFilterTest.java =================================================================== --- branches/2.7.x/modules/library/render/src/test/java/org/geotools/renderer/lite/SpatialFilterTest.java (rev 0) +++ branches/2.7.x/modules/library/render/src/test/java/org/geotools/renderer/lite/SpatialFilterTest.java 2012-05-27 09:12:32 UTC (rev 38762) @@ -0,0 +1,228 @@ +package org.geotools.renderer.lite; + +import static org.junit.Assert.*; + +import java.io.File; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import org.geotools.data.property.PropertyDataStore; +import org.geotools.data.simple.SimpleFeatureSource; +import org.geotools.factory.CommonFactoryFinder; +import org.geotools.factory.Hints; +import org.geotools.geometry.jts.JTS; +import org.geotools.geometry.jts.ReferencedEnvelope; +import org.geotools.map.DefaultMapContext; +import org.geotools.map.FeatureLayer; +import org.geotools.map.MapContent; +import org.geotools.map.MapContext; +import org.geotools.referencing.CRS; +import org.geotools.referencing.CRS.AxisOrder; +import org.geotools.referencing.ReferencingFactoryFinder; +import org.geotools.referencing.crs.DefaultGeographicCRS; +import org.geotools.renderer.RenderListener; +import org.geotools.styling.PolygonSymbolizer; +import org.geotools.styling.Rule; +import org.geotools.styling.Style; +import org.geotools.styling.StyleBuilder; +import org.geotools.styling.Symbolizer; +import org.geotools.test.TestData; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.opengis.feature.simple.SimpleFeature; +import org.opengis.filter.FilterFactory2; +import org.opengis.referencing.crs.CRSAuthorityFactory; +import org.opengis.referencing.crs.CoordinateReferenceSystem; + +import com.vividsolutions.jts.geom.Envelope; +import com.vividsolutions.jts.geom.Polygon; + +public class SpatialFilterTest { + + private static final long TIME = 2000; + + FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2(null); + + SimpleFeatureSource squareFS; + + ReferencedEnvelope bounds; + + StreamingRenderer renderer; + + MapContext context; + + int errorCount = 0; + + Set<String> renderedIds = new HashSet<String>(); + + RenderListener listener; + + SimpleFeatureSource pointFS; + + @Before + public void setUp() throws Exception { + CRS.reset("all"); + Hints.putSystemDefault(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.TRUE); + + // the following is only to make the test work in Eclipse, where the test + // classpath is tainted by the test classpath of dependent modules (whilst in Maven it's not) + Set<CRSAuthorityFactory> factories = ReferencingFactoryFinder.getCRSAuthorityFactories(null); + for (CRSAuthorityFactory factory : factories) { + if(factory.getClass().getSimpleName().equals("EPSGCRSAuthorityFactory")) { + ReferencingFactoryFinder.removeAuthorityFactory(factory); + } + } + assertEquals(AxisOrder.NORTH_EAST, CRS.getAxisOrder(CRS.decode("urn:ogc:def:crs:EPSG::4326"))); + + // setup data + File property = new File(TestData.getResource(this, "square.properties").toURI()); + PropertyDataStore ds = new PropertyDataStore(property.getParentFile()); + squareFS = ds.getFeatureSource("square"); + pointFS = ds.getFeatureSource("point"); + bounds = new ReferencedEnvelope(0, 10, 0, 10, DefaultGeographicCRS.WGS84); + + // prepare the renderer + renderer = new StreamingRenderer(); + context = new DefaultMapContext(DefaultGeographicCRS.WGS84); + + renderer.setContext(context); + renderer.addRenderListener(new RenderListener() { + + public void featureRenderer(SimpleFeature feature) { + renderedIds.add(feature.getID()); + } + + public void errorOccurred(Exception e) { + errorCount++; + } + }); + + // System.setProperty("org.geotools.test.interactive", "true"); + } + + @After + public void tearDown() { + Hints.putSystemDefault(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.FALSE); + } + + @Test + public void testSpatialNoReprojection() throws Exception { + // a spatial filter in the same SRS as the geometry + StyleBuilder sb = new StyleBuilder(); + PolygonSymbolizer ps = sb.createPolygonSymbolizer(); + Style style = sb.createStyle(ps); + Rule rule = style.featureTypeStyles().get(0).rules().get(0); + rule.setFilter(ff.bbox("geom", 1, 1, 4, 4, "EPSG:4326")); + + context.addLayer(new FeatureLayer(squareFS, style)); + + RendererBaseTest.showRender("Spatial with default CRS", renderer, TIME, bounds); + assertEquals(2, renderedIds.size()); + } + + @Test + public void testSpatialDefaulter() throws Exception { + // a spatial filter in the same SRS as the geometry + StyleBuilder sb = new StyleBuilder(); + PolygonSymbolizer ps = sb.createPolygonSymbolizer(); + Style style = sb.createStyle(ps); + Rule rule = style.featureTypeStyles().get(0).rules().get(0); + rule.setFilter(ff.bbox("geom", 1, 1, 4, 4, null)); + + context.addLayer(new FeatureLayer(squareFS, style)); + + RendererBaseTest.showRender("Spatial without CRS", renderer, TIME, bounds); + assertEquals(2, renderedIds.size()); + } + + @Test + public void testSpatialDefaulterForceEPSG() throws Exception { + // a spatial filter in the same SRS as the geometry... but with a different axis order + // interpretation, if we assume lat/lon we should pick point.4 + StyleBuilder sb = new StyleBuilder(); + Symbolizer ps = sb.createPointSymbolizer(); + Style style = sb.createStyle(ps); + Rule rule = style.featureTypeStyles().get(0).rules().get(0); + rule.setFilter(ff.bbox("geom", 5, 1, 7, 3, null)); + + // force EPSG axis order interpretation + renderer.setRendererHints(Collections.singletonMap(StreamingRenderer.FORCE_EPSG_AXIS_ORDER_KEY, true)); + + context.addLayer(new FeatureLayer(pointFS, style)); + + RendererBaseTest.showRender("Spatial in EPSG order", renderer, TIME, bounds); + assertEquals(1, renderedIds.size()); + assertEquals("point.4", renderedIds.iterator().next()); + } + + @Test + public void testReprojectedBBOX() throws Exception { + // a spatial filter in a different SRS + CoordinateReferenceSystem utm31n = CRS.decode("EPSG:32631"); + CoordinateReferenceSystem wgs84 = CRS.decode("EPSG:4326"); + ReferencedEnvelope envWgs84 = new ReferencedEnvelope(1, 3, 5, 7, wgs84); + ReferencedEnvelope envUTM31N = envWgs84.transform(utm31n, true); + + StyleBuilder sb = new StyleBuilder(); + Symbolizer ps = sb.createPointSymbolizer(); + Style style = sb.createStyle(ps); + Rule rule = style.featureTypeStyles().get(0).rules().get(0); + rule.setFilter(ff.bbox("geom", envUTM31N.getMinX(), envUTM31N.getMinY(), envUTM31N.getMaxX(), envUTM31N.getMaxY(), "EPSG:32631")); + + // force EPSG axis order interpretation + renderer.setRendererHints(Collections.singletonMap(StreamingRenderer.FORCE_EPSG_AXIS_ORDER_KEY, true)); + + context.addLayer(new FeatureLayer(pointFS, style)); + + RendererBaseTest.showRender("Spatial in EPSG order", renderer, TIME, bounds); + assertEquals(1, renderedIds.size()); + assertEquals("point.4", renderedIds.iterator().next()); + } + + @Test + public void testReprojectedPolygon() throws Exception { + // a spatial filter in a different SRS + CoordinateReferenceSystem utm31n = CRS.decode("EPSG:32631"); + CoordinateReferenceSystem wgs84 = CRS.decode("EPSG:4326"); + ReferencedEnvelope envWgs84 = new ReferencedEnvelope(1, 3, 5, 7, wgs84); + ReferencedEnvelope envUTM31N = envWgs84.transform(utm31n, true); + + StyleBuilder sb = new StyleBuilder(); + Symbolizer ps = sb.createPointSymbolizer(); + Style style = sb.createStyle(ps); + Rule rule = style.featureTypeStyles().get(0).rules().get(0); + Polygon polygon = JTS.toGeometry((Envelope) envUTM31N); + polygon.setUserData(utm31n); + rule.setFilter(ff.intersects(ff.property("geom"), ff.literal(polygon))); + + // force EPSG axis order interpretation + renderer.setRendererHints(Collections.singletonMap(StreamingRenderer.FORCE_EPSG_AXIS_ORDER_KEY, true)); + + context.addLayer(new FeatureLayer(pointFS, style)); + + RendererBaseTest.showRender("Spatial in EPSG order", renderer, TIME, bounds); + assertEquals(1, renderedIds.size()); + assertEquals("point.4", renderedIds.iterator().next()); + } + + @Test + public void testReprojectedPolygonFromSLD() throws Exception { + // same as above, but with the style in SLD form + Style style = RendererBaseTest.loadStyle(this, "spatialFilter.sld"); + + // force EPSG axis order interpretation + renderer.setRendererHints(Collections.singletonMap(StreamingRenderer.FORCE_EPSG_AXIS_ORDER_KEY, true)); + + context.addLayer(new FeatureLayer(pointFS, style)); + + RendererBaseTest.showRender("Spatial in EPSG order", renderer, TIME, bounds); + assertEquals(1, renderedIds.size()); + assertEquals("point.4", renderedIds.iterator().next()); + } + + + + +} Modified: branches/2.7.x/modules/library/render/src/test/resources/org/geotools/renderer/lite/test-data/point.properties =================================================================== --- branches/2.7.x/modules/library/render/src/test/resources/org/geotools/renderer/lite/test-data/point.properties 2012-05-27 09:11:50 UTC (rev 38761) +++ branches/2.7.x/modules/library/render/src/test/resources/org/geotools/renderer/lite/test-data/point.properties 2012-05-27 09:12:32 UTC (rev 38762) @@ -1,4 +1,4 @@ -_=id:int,geom:Point:4326,code:String,ax:double,ay:double,rotation:double +_=id:int,geom:Point:srid=4326,code:String,ax:double,ay:double,rotation:double point.0=0|POINT(0 0)|U+0021|0|0|0 point.1=1|POINT(2 4)|U+0021|1|1|0 point.2=2|POINT(4 4)|U+0022|1|1|-90 Added: branches/2.7.x/modules/library/render/src/test/resources/org/geotools/renderer/lite/test-data/spatialFilter.sld =================================================================== --- branches/2.7.x/modules/library/render/src/test/resources/org/geotools/renderer/lite/test-data/spatialFilter.sld (rev 0) +++ branches/2.7.x/modules/library/render/src/test/resources/org/geotools/renderer/lite/test-data/spatialFilter.sld 2012-05-27 09:12:32 UTC (rev 38762) @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="UTF-8"?> +<sld:UserStyle xmlns="http://www.opengis.net/sld" + xmlns:sld="http://www.opengis.net/sld" xmlns:ogc="http://www.opengis.net/ogc" + xmlns:gml="http://www.opengis.net/gml"> + <sld:Name>Default Styler</sld:Name> + <sld:Title /> + <sld:FeatureTypeStyle> + <sld:Name>name</sld:Name> + <sld:Rule> + <ogc:Filter> + <ogc:Intersects> + <ogc:PropertyName>geom</ogc:PropertyName> + <gml:Polygon srsName="EPSG:32631"> + <gml:outerBoundaryIs> + <gml:LinearRing> + <gml:coordinates decimal="." cs="," ts=" ">278246.6541,552664.2969 + 500000,552664.2969 500000,774218.9664 + 278246.6541,774218.9664 278246.6541,552664.2969 + </gml:coordinates> + </gml:LinearRing> + </gml:outerBoundaryIs> + </gml:Polygon> + </ogc:Intersects> + </ogc:Filter> + <sld:PointSymbolizer> + <sld:Graphic> + <sld:Mark> + <sld:Fill /> + <sld:Stroke /> + </sld:Mark> + </sld:Graphic> + </sld:PointSymbolizer> + </sld:Rule> + </sld:FeatureTypeStyle> +</sld:UserStyle> \ No newline at end of file Modified: branches/2.7.x/modules/plugin/epsg-hsql/src/test/java/org/geotools/referencing/CRSTest.java =================================================================== --- branches/2.7.x/modules/plugin/epsg-hsql/src/test/java/org/geotools/referencing/CRSTest.java 2012-05-27 09:11:50 UTC (rev 38761) +++ branches/2.7.x/modules/plugin/epsg-hsql/src/test/java/org/geotools/referencing/CRSTest.java 2012-05-27 09:12:32 UTC (rev 38762) @@ -39,6 +39,7 @@ import org.geotools.factory.Hints; import org.geotools.factory.GeoTools; import org.geotools.metadata.iso.citation.Citations; +import org.geotools.referencing.CRS.AxisOrder; import org.geotools.referencing.crs.DefaultGeographicCRS; import org.geotools.referencing.factory.OrderedAxisAuthorityFactory; @@ -416,6 +417,18 @@ } } + public void testSRSAxisOrder2() throws Exception { + try { + Hints.putSystemDefault(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.TRUE); + CoordinateReferenceSystem crsEN = CRS.decode("EPSG:4326"); + assertEquals(AxisOrder.EAST_NORTH, CRS.getAxisOrder(crsEN)); + CoordinateReferenceSystem crsNE = CRS.decode("urn:ogc:def:crs:EPSG::4326"); + assertEquals(AxisOrder.NORTH_EAST, CRS.getAxisOrder(crsNE)); + } finally { + Hints.removeSystemDe... [truncated message content] |
From: <svn...@os...> - 2012-05-27 09:11:59
|
Author: aaime Date: 2012-05-27 02:11:50 -0700 (Sun, 27 May 2012) New Revision: 38761 Added: branches/2.7.x/modules/library/main/src/main/java/org/geotools/filter/visitor/SpatialFilterVisitor.java branches/2.7.x/modules/library/main/src/test/java/org/geotools/filter/visitor/SpatialFilterVisitorTest.java branches/2.7.x/modules/library/main/src/test/resources/org/geotools/filter/test-data/intersectsCRS.xml Modified: branches/2.7.x/modules/library/main/pom.xml branches/2.7.x/modules/library/main/src/main/java/org/geotools/filter/ExpressionDOMParser.java branches/2.7.x/modules/library/main/src/main/java/org/geotools/filter/visitor/SimplifyingFilterVisitor.java branches/2.7.x/modules/library/main/src/main/java/org/geotools/gml/producer/GeometryTransformer.java branches/2.7.x/modules/library/main/src/test/java/org/geotools/filter/DOMParserTest.java branches/2.7.x/modules/library/main/src/test/java/org/geotools/filter/FilterTransformerTest.java Log: [GEOT-4154] Filter to XML and back does not preserve geometry srsName information Modified: branches/2.7.x/modules/library/main/pom.xml =================================================================== --- branches/2.7.x/modules/library/main/pom.xml 2012-05-26 18:47:18 UTC (rev 38760) +++ branches/2.7.x/modules/library/main/pom.xml 2012-05-27 09:11:50 UTC (rev 38761) @@ -233,7 +233,7 @@ </dependency> <dependency> <groupId>org.geotools</groupId> - <artifactId>gt-epsg-wkt</artifactId> + <artifactId>gt-epsg-hsql</artifactId> <version>${project.version}</version> <scope>test</scope> </dependency> Modified: branches/2.7.x/modules/library/main/src/main/java/org/geotools/filter/ExpressionDOMParser.java =================================================================== --- branches/2.7.x/modules/library/main/src/main/java/org/geotools/filter/ExpressionDOMParser.java 2012-05-26 18:47:18 UTC (rev 38760) +++ branches/2.7.x/modules/library/main/src/main/java/org/geotools/filter/ExpressionDOMParser.java 2012-05-27 09:11:50 UTC (rev 38761) @@ -24,9 +24,11 @@ import java.util.logging.Logger; import org.geotools.factory.CommonFactoryFinder; +import org.geotools.referencing.CRS; import org.opengis.filter.FilterFactory2; import org.opengis.filter.expression.Expression; import org.opengis.filter.expression.PropertyName; +import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; @@ -434,13 +436,39 @@ ExpressionDOMParser parser = new ExpressionDOMParser(); return parser.gml( root ); } + + + public Geometry gml(Node root) { + // look for the SRS name, if available + Node srsNameNode = root.getAttributes().getNamedItem("srsName"); + CoordinateReferenceSystem crs = null; + if(srsNameNode != null) { + String srs = srsNameNode.getTextContent(); + try { + crs = CRS.decode(srs); + } catch(Exception e) { + LOGGER.warning("Failed to parse the specified SRS " + srs); + } + } + + // parse the geometry + Geometry g = _gml(root); + + // force the crs if necessary + if(crs != null) { + g.setUserData(crs); + } + + return g; + } + /** * Parses the gml of this node to jts. * * @param root the parent node of the gml to parse. * @return the java representation of the geometry contained in root. */ - public Geometry gml(Node root) { + private Geometry _gml(Node root) { LOGGER.finer("processing gml " + root); List coordList; @@ -453,15 +481,15 @@ //SLDparser. I really would like that class redone, so we don't have //to use this crappy DOM GML parser. String childName = child.getNodeName(); - if(childName == null) - { - childName = child.getLocalName(); - } - if(!childName.startsWith("gml:")) - { - childName = "gml:" + childName; - } - + if(childName == null) + { + childName = child.getLocalName(); + } + if(!childName.startsWith("gml:")) + { + childName = "gml:" + childName; + } + if (childName.equalsIgnoreCase("gml:box")) { type = GML_BOX; coordList = parseCoords(child); Modified: branches/2.7.x/modules/library/main/src/main/java/org/geotools/filter/visitor/SimplifyingFilterVisitor.java =================================================================== --- branches/2.7.x/modules/library/main/src/main/java/org/geotools/filter/visitor/SimplifyingFilterVisitor.java 2012-05-26 18:47:18 UTC (rev 38760) +++ branches/2.7.x/modules/library/main/src/main/java/org/geotools/filter/visitor/SimplifyingFilterVisitor.java 2012-05-27 09:11:50 UTC (rev 38761) @@ -13,7 +13,8 @@ * 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. - */package org.geotools.filter.visitor; + */ +package org.geotools.filter.visitor; import java.util.ArrayList; import java.util.HashSet; Added: branches/2.7.x/modules/library/main/src/main/java/org/geotools/filter/visitor/SpatialFilterVisitor.java =================================================================== --- branches/2.7.x/modules/library/main/src/main/java/org/geotools/filter/visitor/SpatialFilterVisitor.java (rev 0) +++ branches/2.7.x/modules/library/main/src/main/java/org/geotools/filter/visitor/SpatialFilterVisitor.java 2012-05-27 09:11:50 UTC (rev 38761) @@ -0,0 +1,111 @@ +/* + * GeoTools - The Open Source Java GIS Toolkit + * http://geotools.org + * + * (C) 2004-2008, Open Source Geospatial Foundation (OSGeo) + * + * 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; + * 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. + */ +package org.geotools.filter.visitor; + +import org.opengis.filter.spatial.BBOX; +import org.opengis.filter.spatial.Beyond; +import org.opengis.filter.spatial.Contains; +import org.opengis.filter.spatial.Crosses; +import org.opengis.filter.spatial.DWithin; +import org.opengis.filter.spatial.Disjoint; +import org.opengis.filter.spatial.Equals; +import org.opengis.filter.spatial.Intersects; +import org.opengis.filter.spatial.Overlaps; +import org.opengis.filter.spatial.Touches; +import org.opengis.filter.spatial.Within; + +/** + * Filter that can be applied to determine if a Filter contains any spatial filter + * + * @author Andrea Aime - GeoSolutions + * @since 2.7.5 + */ +public class SpatialFilterVisitor extends DefaultFilterVisitor { + + boolean hasSpatialFilter = false; + + /** + * True if the filter had a spatial filter, false otherwise + * @return + */ + public boolean hasSpatialFilter() { + return hasSpatialFilter; + } + + /** + * Resets this visitor so that it can be reused on another filter + */ + public void reset() { + hasSpatialFilter = false; + } + + public Object visit(final BBOX filter, Object data) { + hasSpatialFilter = true; + return data; + } + + public Object visit(Beyond filter, Object data) { + hasSpatialFilter = true; + return data; + } + + public Object visit(Contains filter, Object data) { + hasSpatialFilter = true; + return data; + } + + public Object visit(Crosses filter, Object data) { + hasSpatialFilter = true; + return data; + } + + public Object visit(Disjoint filter, Object data) { + hasSpatialFilter = true; + return data; + } + + public Object visit(DWithin filter, Object data) { + hasSpatialFilter = true; + return data; + } + + public Object visit(Equals filter, Object data) { + hasSpatialFilter = true; + return data; + } + + public Object visit(Intersects filter, Object data) { + hasSpatialFilter = true; + return data; + } + + public Object visit(Overlaps filter, Object data) { + hasSpatialFilter = true; + return data; + } + + public Object visit(Touches filter, Object data) { + hasSpatialFilter = true; + return data; + } + + public Object visit(Within filter, Object data) { + hasSpatialFilter = true; + return data; + } + +} Modified: branches/2.7.x/modules/library/main/src/main/java/org/geotools/gml/producer/GeometryTransformer.java =================================================================== --- branches/2.7.x/modules/library/main/src/main/java/org/geotools/gml/producer/GeometryTransformer.java 2012-05-26 18:47:18 UTC (rev 38760) +++ branches/2.7.x/modules/library/main/src/main/java/org/geotools/gml/producer/GeometryTransformer.java 2012-05-27 09:11:50 UTC (rev 38761) @@ -22,7 +22,13 @@ */ package org.geotools.gml.producer; +import java.util.logging.Logger; + +import org.geotools.referencing.CRS; +import org.geotools.referencing.CRS.AxisOrder; +import org.geotools.util.logging.Logging; import org.geotools.xml.transform.TransformerBase; +import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.xml.sax.ContentHandler; import org.xml.sax.SAXException; import org.xml.sax.helpers.AttributesImpl; @@ -51,6 +57,8 @@ */ public class GeometryTransformer extends TransformerBase { + static final Logger LOGGER = Logging.getLogger(GeometryTransformer.class); + protected boolean useDummyZ = false; protected int numDecimals = 4; @@ -214,7 +222,24 @@ * Encodes the given geometry with no srsName attribute and forcing 2D */ public void encode(Geometry geometry) { - encode(geometry, null); + String srsName = null; + // see if we have a EPSG CRS attached to the geometry + if(geometry.getUserData() instanceof CoordinateReferenceSystem) { + try { + CoordinateReferenceSystem crs = (CoordinateReferenceSystem) geometry.getUserData(); + Integer code = CRS.lookupEpsgCode(crs, false); + if(code != null) { + if(AxisOrder.NORTH_EAST.equals(CRS.getAxisOrder(crs))) { + srsName = "urn:ogc:def:crs:EPSG::" + code; + } else { + srsName = "EPSG:" + code; + } + } + } catch(Exception e) { + LOGGER.fine("Failed to encode the CoordinateReferenceSystem into a srsName"); + } + } + encode(geometry, srsName); } /** Modified: branches/2.7.x/modules/library/main/src/test/java/org/geotools/filter/DOMParserTest.java =================================================================== --- branches/2.7.x/modules/library/main/src/test/java/org/geotools/filter/DOMParserTest.java 2012-05-26 18:47:18 UTC (rev 38760) +++ branches/2.7.x/modules/library/main/src/test/java/org/geotools/filter/DOMParserTest.java 2012-05-27 09:11:50 UTC (rev 38761) @@ -29,6 +29,7 @@ import org.geotools.feature.SchemaException; import org.geotools.feature.simple.SimpleFeatureBuilder; import org.geotools.feature.simple.SimpleFeatureTypeBuilder; +import org.geotools.referencing.CRS; import org.geotools.test.TestData; import org.opengis.filter.Filter; import org.opengis.filter.PropertyIsNotEqualTo; @@ -37,6 +38,8 @@ import org.opengis.filter.spatial.Beyond; import org.opengis.filter.spatial.Crosses; import org.opengis.filter.spatial.DWithin; +import org.opengis.filter.spatial.Intersects; +import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; @@ -46,6 +49,7 @@ import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.LineString; import com.vividsolutions.jts.geom.Point; +import com.vividsolutions.jts.geom.Polygon; /** * Tests for the DOM parser. @@ -246,6 +250,17 @@ assertTrue(((Literal) cr.getExpression2()).getValue() instanceof LineString); LOGGER.fine("parsed filter is " + test); } + + public void testIntersectsCRS() throws Exception { + Filter test = parseDocument("intersectsCRS.xml"); + assertTrue(test instanceof Intersects); + Intersects cr = (Intersects) test; + assertEquals("geom", ((PropertyName) cr.getExpression1()).getPropertyName()); + Polygon p = (Polygon) ((Literal) cr.getExpression2()).getValue(); + assertTrue(p.getUserData() instanceof CoordinateReferenceSystem); + int epsg = CRS.lookupEpsgCode((CoordinateReferenceSystem) p.getUserData(), false); + assertEquals(32631, epsg); + } public void test28() throws Exception { FidFilter filter = (FidFilter) parseDocumentFirst("test28.xml"); Modified: branches/2.7.x/modules/library/main/src/test/java/org/geotools/filter/FilterTransformerTest.java =================================================================== --- branches/2.7.x/modules/library/main/src/test/java/org/geotools/filter/FilterTransformerTest.java 2012-05-26 18:47:18 UTC (rev 38760) +++ branches/2.7.x/modules/library/main/src/test/java/org/geotools/filter/FilterTransformerTest.java 2012-05-27 09:11:50 UTC (rev 38761) @@ -16,42 +16,94 @@ */ package org.geotools.filter; +import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; import junit.framework.TestCase; +import org.custommonkey.xmlunit.SimpleNamespaceContext; +import org.custommonkey.xmlunit.XMLAssert; +import org.custommonkey.xmlunit.XMLUnit; import org.geotools.factory.CommonFactoryFinder; +import org.geotools.referencing.CRS; +import org.geotools.referencing.CRS.AxisOrder; +import org.geotools.referencing.ReferencingFactoryFinder; import org.opengis.filter.Filter; import org.opengis.filter.FilterFactory2; import org.opengis.filter.identity.FeatureId; +import org.opengis.referencing.crs.CRSAuthorityFactory; +import org.opengis.referencing.crs.CoordinateReferenceSystem; +import org.w3c.dom.Document; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.io.WKTReader; public class FilterTransformerTest extends TestCase { FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2(null); + FilterTransformer transform = new FilterTransformer(); + + @Override + protected void setUp() throws Exception { + // init xmlunit + Map<String, String> namespaces = new HashMap<String, String>(); + namespaces.put("ogc", "http://www.opengis.net/ogc"); + namespaces.put("gml", "http://www.opengis.net/gml"); + namespaces.put("xsi", "http://www.w3.org/2001/XMLSchema-instance"); + + XMLUnit.setXpathNamespaceContext(new SimpleNamespaceContext(namespaces)); } public void testIdEncode() throws Exception { HashSet<FeatureId> set = new LinkedHashSet<FeatureId>(); - set.add( ff.featureId("FID.1")); - set.add( ff.featureId("FID.2")); - Filter filter=ff.id( set ); - - String output = transform.transform( filter ); - assertNotNull( "got xml", output ); + set.add(ff.featureId("FID.1")); + set.add(ff.featureId("FID.2")); + Filter filter = ff.id(set); + + String output = transform.transform(filter); + assertNotNull("got xml", output); String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><ogc:FeatureId xmlns=\"http://www.opengis.net/ogc\" xmlns:ogc=\"http://www.opengis.net/ogc\" xmlns:gml=\"http://www.opengis.net/gml\" fid=\"FID.1\"/><ogc:FeatureId fid=\"FID.2\"/>"; - assertEquals( "expected id filters", xml, output ); + assertEquals("expected id filters", xml, output); } - + public void testEncodeLong() throws Exception { Filter filter = ff.greater(ff.property("MYATT"), ff.literal(50000000l)); - String output = transform.transform( filter ); - assertNotNull( "got xml", output ); - String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><ogc:PropertyIsGreaterThan " + - "xmlns=\"http://www.opengis.net/ogc\" xmlns:ogc=\"http://www.opengis.net/ogc\" " + - "xmlns:gml=\"http://www.opengis.net/gml\">" + - "<ogc:PropertyName>MYATT</ogc:PropertyName>" + - "<ogc:Literal>50000000</ogc:Literal></ogc:PropertyIsGreaterThan>"; + String output = transform.transform(filter); + assertNotNull("got xml", output); + String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><ogc:PropertyIsGreaterThan " + + "xmlns=\"http://www.opengis.net/ogc\" xmlns:ogc=\"http://www.opengis.net/ogc\" " + + "xmlns:gml=\"http://www.opengis.net/gml\">" + + "<ogc:PropertyName>MYATT</ogc:PropertyName>" + + "<ogc:Literal>50000000</ogc:Literal></ogc:PropertyIsGreaterThan>"; assertEquals(xml, output); } + + public void testEncodeSRSNameLonLat() throws Exception { + // create a georeferenced geometry + CoordinateReferenceSystem wgs84 = CRS.decode("EPSG:4326", true); + Geometry point = new WKTReader().read("POINT(10 0)"); + point.setUserData(wgs84); + + // a filter on top of it + Filter filter = ff.overlaps(ff.property("geom"), ff.literal(point)); + String output = transform.transform(filter); + Document doc = XMLUnit.buildControlDocument(output); + XMLAssert.assertXpathEvaluatesTo("EPSG:4326", "//gml:Point/@srsName", doc); + } + + public void testEncodeSRSNameLatLon() throws Exception { + // create a georeferenced geometry + CoordinateReferenceSystem wgs84 = CRS.decode("urn:ogc:def:crs:EPSG::4326"); + System.out.println(wgs84); + Geometry point = new WKTReader().read("POINT(10 0)"); + point.setUserData(wgs84); + + // a filter on top of it + Filter filter = ff.overlaps(ff.property("geom"), ff.literal(point)); + String output = transform.transform(filter); + Document doc = XMLUnit.buildControlDocument(output); + XMLAssert.assertXpathEvaluatesTo("urn:ogc:def:crs:EPSG::4326", "//gml:Point/@srsName", doc); + } } Added: branches/2.7.x/modules/library/main/src/test/java/org/geotools/filter/visitor/SpatialFilterVisitorTest.java =================================================================== --- branches/2.7.x/modules/library/main/src/test/java/org/geotools/filter/visitor/SpatialFilterVisitorTest.java (rev 0) +++ branches/2.7.x/modules/library/main/src/test/java/org/geotools/filter/visitor/SpatialFilterVisitorTest.java 2012-05-27 09:11:50 UTC (rev 38761) @@ -0,0 +1,53 @@ +package org.geotools.filter.visitor; + +import static org.junit.Assert.*; + +import org.geotools.factory.CommonFactoryFinder; +import org.junit.Before; +import org.junit.Test; +import org.opengis.filter.Filter; +import org.opengis.filter.FilterFactory2; + + +public class SpatialFilterVisitorTest { + + FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2(null); + private SpatialFilterVisitor visitor; + + + @Before + public void setUp() throws Exception { + visitor = new SpatialFilterVisitor(); + } + + @Test + public void testInclude() { + Filter.INCLUDE.accept(visitor, null); + assertFalse(visitor.hasSpatialFilter); + } + + @Test + public void testExclude() { + Filter.EXCLUDE.accept(visitor, null); + assertFalse(visitor.hasSpatialFilter); + } + + @Test + public void testBBOX() { + ff.bbox("geom", 0, 0, 10, 10, "EPSG:4326").accept(visitor, null); + assertTrue(visitor.hasSpatialFilter); + } + + @Test + public void testIntersects() { + ff.intersects(ff.property("geom"), ff.literal(null)).accept(visitor, null); + assertTrue(visitor.hasSpatialFilter); + } + + @Test + public void testOverlaps() { + ff.overlaps(ff.property("geom"), ff.literal(null)).accept(visitor, null); + assertTrue(visitor.hasSpatialFilter); + } + +} Added: branches/2.7.x/modules/library/main/src/test/resources/org/geotools/filter/test-data/intersectsCRS.xml =================================================================== --- branches/2.7.x/modules/library/main/src/test/resources/org/geotools/filter/test-data/intersectsCRS.xml (rev 0) +++ branches/2.7.x/modules/library/main/src/test/resources/org/geotools/filter/test-data/intersectsCRS.xml 2012-05-27 09:11:50 UTC (rev 38761) @@ -0,0 +1,16 @@ +<Filter> + <Intersects> + <PropertyName>geom</PropertyName> + <gml:Polygon xmlns:gml="http://www.opengis.net/gml" + srsName="EPSG:32631"> + <gml:outerBoundaryIs> + <gml:LinearRing> + <gml:coordinates decimal="." cs="," ts=" ">278246.6541,552664.2969 + 500000,552664.2969 500000,774218.9664 + 278246.6541,774218.9664 278246.6541,552664.2969 + </gml:coordinates> + </gml:LinearRing> + </gml:outerBoundaryIs> + </gml:Polygon> + </Intersects> +</Filter> \ No newline at end of file |
From: <svn...@os...> - 2012-05-26 18:47:25
|
Author: aaime Date: 2012-05-26 11:47:18 -0700 (Sat, 26 May 2012) New Revision: 38760 Added: trunk/modules/library/render/src/test/resources/org/geotools/renderer/lite/test-data/spatialFilter.sld Log: Adding missing file to the last commit Added: trunk/modules/library/render/src/test/resources/org/geotools/renderer/lite/test-data/spatialFilter.sld =================================================================== --- trunk/modules/library/render/src/test/resources/org/geotools/renderer/lite/test-data/spatialFilter.sld (rev 0) +++ trunk/modules/library/render/src/test/resources/org/geotools/renderer/lite/test-data/spatialFilter.sld 2012-05-26 18:47:18 UTC (rev 38760) @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="UTF-8"?> +<sld:UserStyle xmlns="http://www.opengis.net/sld" + xmlns:sld="http://www.opengis.net/sld" xmlns:ogc="http://www.opengis.net/ogc" + xmlns:gml="http://www.opengis.net/gml"> + <sld:Name>Default Styler</sld:Name> + <sld:Title /> + <sld:FeatureTypeStyle> + <sld:Name>name</sld:Name> + <sld:Rule> + <ogc:Filter> + <ogc:Intersects> + <ogc:PropertyName>geom</ogc:PropertyName> + <gml:Polygon srsName="EPSG:32631"> + <gml:outerBoundaryIs> + <gml:LinearRing> + <gml:coordinates decimal="." cs="," ts=" ">278246.6541,552664.2969 + 500000,552664.2969 500000,774218.9664 + 278246.6541,774218.9664 278246.6541,552664.2969 + </gml:coordinates> + </gml:LinearRing> + </gml:outerBoundaryIs> + </gml:Polygon> + </ogc:Intersects> + </ogc:Filter> + <sld:PointSymbolizer> + <sld:Graphic> + <sld:Mark> + <sld:Fill /> + <sld:Stroke /> + </sld:Mark> + </sld:Graphic> + </sld:PointSymbolizer> + </sld:Rule> + </sld:FeatureTypeStyle> +</sld:UserStyle> \ No newline at end of file |
From: <svn...@os...> - 2012-05-26 18:46:49
|
Author: aaime Date: 2012-05-26 11:46:42 -0700 (Sat, 26 May 2012) New Revision: 38759 Modified: trunk/modules/library/render/src/main/java/org/geotools/renderer/lite/StreamingRenderer.java trunk/modules/library/render/src/test/java/org/geotools/renderer/lite/SpatialFilterTest.java trunk/modules/library/render/src/test/resources/org/geotools/renderer/lite/test-data/point.properties trunk/modules/plugin/epsg-hsql/src/test/java/org/geotools/referencing/CRSTest.java Log: [GEOT-4155] Renderer does not handle spatial filters in projections others than the native data one Modified: trunk/modules/library/render/src/main/java/org/geotools/renderer/lite/StreamingRenderer.java =================================================================== --- trunk/modules/library/render/src/main/java/org/geotools/renderer/lite/StreamingRenderer.java 2012-05-26 18:46:14 UTC (rev 38758) +++ trunk/modules/library/render/src/main/java/org/geotools/renderer/lite/StreamingRenderer.java 2012-05-26 18:46:42 UTC (rev 38759) @@ -73,8 +73,11 @@ import org.geotools.filter.IllegalFilterException; import org.geotools.filter.function.GeometryTransformationVisitor; import org.geotools.filter.function.RenderingTransformation; +import org.geotools.filter.spatial.DefaultCRSFilterVisitor; +import org.geotools.filter.spatial.ReprojectingFilterVisitor; import org.geotools.filter.visitor.ExtractBoundsFilterVisitor; import org.geotools.filter.visitor.SimplifyingFilterVisitor; +import org.geotools.filter.visitor.SpatialFilterVisitor; import org.geotools.geometry.GeneralEnvelope; import org.geotools.geometry.jts.Decimator; import org.geotools.geometry.jts.GeometryClipper; @@ -109,8 +112,10 @@ import org.geotools.styling.PointSymbolizer; import org.geotools.styling.RasterSymbolizer; import org.geotools.styling.Rule; +import org.geotools.styling.RuleImpl; import org.geotools.styling.Style; import org.geotools.styling.StyleAttributeExtractor; +import org.geotools.styling.StyleFactory; import org.geotools.styling.Symbolizer; import org.geotools.styling.TextSymbolizer; import org.geotools.styling.visitor.DuplicatingStyleVisitor; @@ -363,6 +368,7 @@ private static boolean VECTOR_RENDERING_ENABLED_DEFAULT = false; public static final String LABEL_CACHE_KEY = "labelCache"; + public static final String FORCE_EPSG_AXIS_ORDER_KEY = "ForceEPSGAxisOrder"; public static final String DPI_KEY = "dpi"; public static final String DECLARED_SCALE_DENOM_KEY = "declaredScaleDenominator"; public static final String SCALE_COMPUTATION_METHOD_KEY = "scaleComputationMethod"; @@ -374,7 +380,10 @@ * and the displayed area of the map. * "dpi" - Integer number of dots per inch of the display 90 DPI is the default (as declared by OGC) * "forceCRS" - CoordinateReferenceSystem declares to the renderer that all layers are of the CRS declared in this hint - * "labelCache" - Declares the label cache that will be used by the renderer. + * "labelCache" - Declares the label cache that will be used by the renderer. + * "forceEPSGAxisOrder" - When doing spatial filter reprojection (from the SLD towards the native CRS) assume the geometries + * are expressed with the axis order suggested by the official EPSG database, regardless of how the + * CRS system might be configured */ private Map rendererHints = null; @@ -1358,7 +1367,23 @@ return false; return Boolean.TRUE.equals(result); } + + /** + * Checks if the geometries in spatial filters in the SLD must be assumed to be expressed + * in the official EPSG axis order, regardless of how the referencing subsystem is configured + * (this is required to support filter reprojection in WMS 1.3+) + * @return + */ + private boolean isEPSGAxisOrderForced() { + if (rendererHints == null) + return false; + Object result = rendererHints.get(FORCE_EPSG_AXIS_ORDER_KEY); + if (result == null) + return false; + return Boolean.TRUE.equals(result); + } + /** * Checks if vector rendering is enabled or not. * See {@link SLDStyleFactory#isVectorRenderingEnabled()} for a full explanation. @@ -1929,6 +1954,10 @@ if(lfts.isEmpty()) return; + // make sure all spatial filters in the feature source native SRS + reprojectSpatialFilters(lfts, featureSource); + + // apply the uom and dpi rescale applyUnitRescale(lfts); // classify by transformation @@ -2300,6 +2329,76 @@ } /** + * Reprojects the spatial filters in each {@link LiteFeatureTypeStyle} so that they match + * the feature source native coordinate system + * @param lfts + * @param fs + * @throws FactoryException + */ + void reprojectSpatialFilters(final ArrayList<LiteFeatureTypeStyle> lfts, FeatureSource fs) throws FactoryException { + // compute the default SRS of the feature source + FeatureType schema = fs.getSchema(); + CoordinateReferenceSystem declaredCRS = schema.getCoordinateReferenceSystem(); + if(isEPSGAxisOrderForced()) { + Integer code = CRS.lookupEpsgCode(declaredCRS, false); + if(code != null) { + declaredCRS = CRS.decode("urn:ogc:def:crs:EPSG::" + code); + } + } + + // reproject spatial filters in each fts + for (LiteFeatureTypeStyle fts : lfts) { + reprojectSpatialFilters(fts, declaredCRS, schema); + } + } + + /** + * Reprojects spatial filters so that they match the feature source native CRS, and assuming all literal + * geometries are specified in the specified declaredCRS + */ + void reprojectSpatialFilters(LiteFeatureTypeStyle fts, CoordinateReferenceSystem declaredCRS, FeatureType schema) { + for (int i = 0; i < fts.ruleList.length; i++) { + fts.ruleList[i] = reprojectSpatialFilters(fts.ruleList[i], declaredCRS, schema); + } + if(fts.elseRules != null) { + for (int i = 0; i < fts.elseRules.length; i++) { + fts.elseRules[i] = reprojectSpatialFilters(fts.elseRules[i], declaredCRS, schema); + } + } + } + + /** + * Reprojects spatial filters so that they match the feature source native CRS, and assuming all literal + * geometries are specified in the specified declaredCRS + */ + private Rule reprojectSpatialFilters(Rule rule, CoordinateReferenceSystem declaredCRS, FeatureType schema) { + // NPE avoidance + Filter filter = rule.getFilter(); + if(filter == null) { + return rule; + } + + // do we have any spatial filter? + SpatialFilterVisitor sfv = new SpatialFilterVisitor(); + filter.accept(sfv, null); + if(!sfv.hasSpatialFilter()) { + return rule; + } + + // all right, we need to default the literals to the declaredCRS and then reproject to + // the native one + DefaultCRSFilterVisitor defaulter = new DefaultCRSFilterVisitor(filterFactory, declaredCRS); + Filter defaulted = (Filter) filter.accept(defaulter, null); + ReprojectingFilterVisitor reprojector = new ReprojectingFilterVisitor(filterFactory, schema); + Filter reprojected = (Filter) defaulted.accept(reprojector, null); + + // clone the rule (the style can be reused over and over, we cannot alter it) and set the new filter + Rule rr = new RuleImpl(rule); + rr.setFilter(reprojected); + return rr; + } + + /** * Utility method to apply the two rescale visitors without duplicating code * @param fts * @param visitor Modified: trunk/modules/library/render/src/test/java/org/geotools/renderer/lite/SpatialFilterTest.java =================================================================== --- trunk/modules/library/render/src/test/java/org/geotools/renderer/lite/SpatialFilterTest.java 2012-05-26 18:46:14 UTC (rev 38758) +++ trunk/modules/library/render/src/test/java/org/geotools/renderer/lite/SpatialFilterTest.java 2012-05-26 18:46:42 UTC (rev 38759) @@ -3,26 +3,40 @@ import static org.junit.Assert.*; import java.io.File; +import java.util.Collections; import java.util.HashSet; import java.util.Set; import org.geotools.data.property.PropertyDataStore; import org.geotools.data.simple.SimpleFeatureSource; import org.geotools.factory.CommonFactoryFinder; +import org.geotools.factory.Hints; +import org.geotools.geometry.jts.JTS; import org.geotools.geometry.jts.ReferencedEnvelope; import org.geotools.map.FeatureLayer; import org.geotools.map.MapContent; +import org.geotools.referencing.CRS; +import org.geotools.referencing.CRS.AxisOrder; +import org.geotools.referencing.ReferencingFactoryFinder; import org.geotools.referencing.crs.DefaultGeographicCRS; import org.geotools.renderer.RenderListener; import org.geotools.styling.PolygonSymbolizer; import org.geotools.styling.Rule; +import org.geotools.styling.SLDTransformer; import org.geotools.styling.Style; import org.geotools.styling.StyleBuilder; +import org.geotools.styling.Symbolizer; import org.geotools.test.TestData; +import org.junit.After; import org.junit.Before; +import org.junit.Test; import org.opengis.feature.simple.SimpleFeature; import org.opengis.filter.FilterFactory2; +import org.opengis.referencing.crs.CRSAuthorityFactory; +import org.opengis.referencing.crs.CoordinateReferenceSystem; +import com.vividsolutions.jts.geom.Polygon; + public class SpatialFilterTest { private static final long TIME = 2000; @@ -43,12 +57,28 @@ RenderListener listener; + SimpleFeatureSource pointFS; + @Before public void setUp() throws Exception { + CRS.reset("all"); + Hints.putSystemDefault(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.TRUE); + + // the following is only to make the test work in Eclipse, where the test + // classpath is tainted by the test classpath of dependent modules (whilst in Maven it's not) + Set<CRSAuthorityFactory> factories = ReferencingFactoryFinder.getCRSAuthorityFactories(null); + for (CRSAuthorityFactory factory : factories) { + if(factory.getClass().getSimpleName().equals("EPSGCRSAuthorityFactory")) { + ReferencingFactoryFinder.removeAuthorityFactory(factory); + } + } + assertEquals(AxisOrder.NORTH_EAST, CRS.getAxisOrder(CRS.decode("urn:ogc:def:crs:EPSG::4326"))); + // setup data File property = new File(TestData.getResource(this, "square.properties").toURI()); PropertyDataStore ds = new PropertyDataStore(property.getParentFile()); squareFS = ds.getFeatureSource("square"); + pointFS = ds.getFeatureSource("point"); bounds = new ReferencedEnvelope(0, 10, 0, 10, DefaultGeographicCRS.WGS84); // prepare the renderer @@ -56,6 +86,7 @@ content = new MapContent(); content.getViewport().setCoordinateReferenceSystem(DefaultGeographicCRS.WGS84); + renderer.setMapContent(content); renderer.addRenderListener(new RenderListener() { public void featureRenderer(SimpleFeature feature) { @@ -66,19 +97,131 @@ errorCount++; } }); + + // System.setProperty("org.geotools.test.interactive", "true"); } + + @After + public void tearDown() { + Hints.putSystemDefault(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.FALSE); + } + @Test public void testSpatialNoReprojection() throws Exception { // a spatial filter in the same SRS as the geometry StyleBuilder sb = new StyleBuilder(); PolygonSymbolizer ps = sb.createPolygonSymbolizer(); Style style = sb.createStyle(ps); Rule rule = style.featureTypeStyles().get(0).rules().get(0); - rule.setFilter(ff.bbox("geom", 1, 1, 4, 4, "EPSG:4326)")); + rule.setFilter(ff.bbox("geom", 1, 1, 4, 4, "EPSG:4326")); content.addLayer(new FeatureLayer(squareFS, style)); - RendererBaseTest.showRender("OneSquare", renderer, TIME, bounds); + RendererBaseTest.showRender("Spatial with default CRS", renderer, TIME, bounds); assertEquals(2, renderedIds.size()); } + + @Test + public void testSpatialDefaulter() throws Exception { + // a spatial filter in the same SRS as the geometry + StyleBuilder sb = new StyleBuilder(); + PolygonSymbolizer ps = sb.createPolygonSymbolizer(); + Style style = sb.createStyle(ps); + Rule rule = style.featureTypeStyles().get(0).rules().get(0); + rule.setFilter(ff.bbox("geom", 1, 1, 4, 4, null)); + + content.addLayer(new FeatureLayer(squareFS, style)); + + RendererBaseTest.showRender("Spatial without CRS", renderer, TIME, bounds); + assertEquals(2, renderedIds.size()); + } + + @Test + public void testSpatialDefaulterForceEPSG() throws Exception { + // a spatial filter in the same SRS as the geometry... but with a different axis order + // interpretation, if we assume lat/lon we should pick point.4 + StyleBuilder sb = new StyleBuilder(); + Symbolizer ps = sb.createPointSymbolizer(); + Style style = sb.createStyle(ps); + Rule rule = style.featureTypeStyles().get(0).rules().get(0); + rule.setFilter(ff.bbox("geom", 5, 1, 7, 3, null)); + + // force EPSG axis order interpretation + renderer.setRendererHints(Collections.singletonMap(StreamingRenderer.FORCE_EPSG_AXIS_ORDER_KEY, true)); + + content.addLayer(new FeatureLayer(pointFS, style)); + + RendererBaseTest.showRender("Spatial in EPSG order", renderer, TIME, bounds); + assertEquals(1, renderedIds.size()); + assertEquals("point.4", renderedIds.iterator().next()); + } + + @Test + public void testReprojectedBBOX() throws Exception { + // a spatial filter in a different SRS + CoordinateReferenceSystem utm31n = CRS.decode("EPSG:32631"); + CoordinateReferenceSystem wgs84 = CRS.decode("EPSG:4326"); + ReferencedEnvelope envWgs84 = new ReferencedEnvelope(1, 3, 5, 7, wgs84); + ReferencedEnvelope envUTM31N = envWgs84.transform(utm31n, true); + + StyleBuilder sb = new StyleBuilder(); + Symbolizer ps = sb.createPointSymbolizer(); + Style style = sb.createStyle(ps); + Rule rule = style.featureTypeStyles().get(0).rules().get(0); + rule.setFilter(ff.bbox("geom", envUTM31N.getMinX(), envUTM31N.getMinY(), envUTM31N.getMaxX(), envUTM31N.getMaxY(), "EPSG:32631")); + + // force EPSG axis order interpretation + renderer.setRendererHints(Collections.singletonMap(StreamingRenderer.FORCE_EPSG_AXIS_ORDER_KEY, true)); + + content.addLayer(new FeatureLayer(pointFS, style)); + + RendererBaseTest.showRender("Spatial in EPSG order", renderer, TIME, bounds); + assertEquals(1, renderedIds.size()); + assertEquals("point.4", renderedIds.iterator().next()); + } + + @Test + public void testReprojectedPolygon() throws Exception { + // a spatial filter in a different SRS + CoordinateReferenceSystem utm31n = CRS.decode("EPSG:32631"); + CoordinateReferenceSystem wgs84 = CRS.decode("EPSG:4326"); + ReferencedEnvelope envWgs84 = new ReferencedEnvelope(1, 3, 5, 7, wgs84); + ReferencedEnvelope envUTM31N = envWgs84.transform(utm31n, true); + + StyleBuilder sb = new StyleBuilder(); + Symbolizer ps = sb.createPointSymbolizer(); + Style style = sb.createStyle(ps); + Rule rule = style.featureTypeStyles().get(0).rules().get(0); + Polygon polygon = JTS.toGeometry(envUTM31N); + polygon.setUserData(utm31n); + rule.setFilter(ff.intersects(ff.property("geom"), ff.literal(polygon))); + + // force EPSG axis order interpretation + renderer.setRendererHints(Collections.singletonMap(StreamingRenderer.FORCE_EPSG_AXIS_ORDER_KEY, true)); + + content.addLayer(new FeatureLayer(pointFS, style)); + + RendererBaseTest.showRender("Spatial in EPSG order", renderer, TIME, bounds); + assertEquals(1, renderedIds.size()); + assertEquals("point.4", renderedIds.iterator().next()); + } + + @Test + public void testReprojectedPolygonFromSLD() throws Exception { + // same as above, but with the style in SLD form + Style style = RendererBaseTest.loadStyle(this, "spatialFilter.sld"); + + // force EPSG axis order interpretation + renderer.setRendererHints(Collections.singletonMap(StreamingRenderer.FORCE_EPSG_AXIS_ORDER_KEY, true)); + + content.addLayer(new FeatureLayer(pointFS, style)); + + RendererBaseTest.showRender("Spatial in EPSG order", renderer, TIME, bounds); + assertEquals(1, renderedIds.size()); + assertEquals("point.4", renderedIds.iterator().next()); + } + + + + } Modified: trunk/modules/library/render/src/test/resources/org/geotools/renderer/lite/test-data/point.properties =================================================================== --- trunk/modules/library/render/src/test/resources/org/geotools/renderer/lite/test-data/point.properties 2012-05-26 18:46:14 UTC (rev 38758) +++ trunk/modules/library/render/src/test/resources/org/geotools/renderer/lite/test-data/point.properties 2012-05-26 18:46:42 UTC (rev 38759) @@ -1,4 +1,4 @@ -_=id:int,geom:Point:4326,code:String,ax:double,ay:double,rotation:double +_=id:int,geom:Point:srid=4326,code:String,ax:double,ay:double,rotation:double point.0=0|POINT(0 0)|U+0021|0|0|0 point.1=1|POINT(2 4)|U+0021|1|1|0 point.2=2|POINT(4 4)|U+0022|1|1|-90 Modified: trunk/modules/plugin/epsg-hsql/src/test/java/org/geotools/referencing/CRSTest.java =================================================================== --- trunk/modules/plugin/epsg-hsql/src/test/java/org/geotools/referencing/CRSTest.java 2012-05-26 18:46:14 UTC (rev 38758) +++ trunk/modules/plugin/epsg-hsql/src/test/java/org/geotools/referencing/CRSTest.java 2012-05-26 18:46:42 UTC (rev 38759) @@ -39,6 +39,7 @@ import org.geotools.factory.Hints; import org.geotools.factory.GeoTools; import org.geotools.metadata.iso.citation.Citations; +import org.geotools.referencing.CRS.AxisOrder; import org.geotools.referencing.crs.DefaultGeographicCRS; import org.geotools.referencing.factory.OrderedAxisAuthorityFactory; @@ -417,6 +418,18 @@ } } + public void testSRSAxisOrder2() throws Exception { + try { + Hints.putSystemDefault(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.TRUE); + CoordinateReferenceSystem crsEN = CRS.decode("EPSG:4326"); + assertEquals(AxisOrder.EAST_NORTH, CRS.getAxisOrder(crsEN)); + CoordinateReferenceSystem crsNE = CRS.decode("urn:ogc:def:crs:EPSG::4326"); + assertEquals(AxisOrder.NORTH_EAST, CRS.getAxisOrder(crsNE)); + } finally { + Hints.removeSystemDefault(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER); + } + } + /** * Tests similarity transform on the example provided in the EPSG projection guide, page 99 * @throws Exception |
From: <svn...@os...> - 2012-05-26 18:46:23
|
Author: aaime Date: 2012-05-26 11:46:14 -0700 (Sat, 26 May 2012) New Revision: 38758 Added: trunk/modules/library/main/src/main/java/org/geotools/filter/visitor/SpatialFilterVisitor.java trunk/modules/library/main/src/test/java/org/geotools/filter/visitor/SpatialFilterVisitorTest.java trunk/modules/library/main/src/test/resources/org/geotools/filter/test-data/intersectsCRS.xml trunk/modules/library/render/src/test/java/org/geotools/renderer/lite/SpatialFilterTest.java Modified: trunk/modules/library/main/src/main/java/org/geotools/filter/ExpressionDOMParser.java trunk/modules/library/main/src/main/java/org/geotools/filter/visitor/SimplifyingFilterVisitor.java trunk/modules/library/main/src/main/java/org/geotools/gml/producer/GeometryTransformer.java trunk/modules/library/main/src/test/java/org/geotools/filter/DOMParserTest.java trunk/modules/library/main/src/test/java/org/geotools/filter/FilterTransformerTest.java Log: [GEOT-4154] Filter to XML and back does not preserve geometry srsName information Modified: trunk/modules/library/main/src/main/java/org/geotools/filter/ExpressionDOMParser.java =================================================================== --- trunk/modules/library/main/src/main/java/org/geotools/filter/ExpressionDOMParser.java 2012-05-25 08:10:24 UTC (rev 38757) +++ trunk/modules/library/main/src/main/java/org/geotools/filter/ExpressionDOMParser.java 2012-05-26 18:46:14 UTC (rev 38758) @@ -24,9 +24,11 @@ import java.util.logging.Logger; import org.geotools.factory.CommonFactoryFinder; +import org.geotools.referencing.CRS; import org.opengis.filter.FilterFactory2; import org.opengis.filter.expression.Expression; import org.opengis.filter.expression.PropertyName; +import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; @@ -463,13 +465,39 @@ ExpressionDOMParser parser = new ExpressionDOMParser(); return parser.gml( root ); } + + + public Geometry gml(Node root) { + // look for the SRS name, if available + Node srsNameNode = root.getAttributes().getNamedItem("srsName"); + CoordinateReferenceSystem crs = null; + if(srsNameNode != null) { + String srs = srsNameNode.getTextContent(); + try { + crs = CRS.decode(srs); + } catch(Exception e) { + LOGGER.warning("Failed to parse the specified SRS " + srs); + } + } + + // parse the geometry + Geometry g = _gml(root); + + // force the crs if necessary + if(crs != null) { + g.setUserData(crs); + } + + return g; + } + /** * Parses the gml of this node to jts. * * @param root the parent node of the gml to parse. * @return the java representation of the geometry contained in root. */ - public Geometry gml(Node root) { + private Geometry _gml(Node root) { LOGGER.finer("processing gml " + root); List coordList; @@ -482,15 +510,15 @@ //SLDparser. I really would like that class redone, so we don't have //to use this crappy DOM GML parser. String childName = child.getNodeName(); - if(childName == null) - { - childName = child.getLocalName(); - } - if(!childName.startsWith("gml:")) - { - childName = "gml:" + childName; - } - + if(childName == null) + { + childName = child.getLocalName(); + } + if(!childName.startsWith("gml:")) + { + childName = "gml:" + childName; + } + if (childName.equalsIgnoreCase("gml:box")) { type = GML_BOX; coordList = parseCoords(child); Modified: trunk/modules/library/main/src/main/java/org/geotools/filter/visitor/SimplifyingFilterVisitor.java =================================================================== --- trunk/modules/library/main/src/main/java/org/geotools/filter/visitor/SimplifyingFilterVisitor.java 2012-05-25 08:10:24 UTC (rev 38757) +++ trunk/modules/library/main/src/main/java/org/geotools/filter/visitor/SimplifyingFilterVisitor.java 2012-05-26 18:46:14 UTC (rev 38758) @@ -13,7 +13,8 @@ * 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. - */package org.geotools.filter.visitor; + */ +package org.geotools.filter.visitor; import java.util.ArrayList; import java.util.HashSet; Added: trunk/modules/library/main/src/main/java/org/geotools/filter/visitor/SpatialFilterVisitor.java =================================================================== --- trunk/modules/library/main/src/main/java/org/geotools/filter/visitor/SpatialFilterVisitor.java (rev 0) +++ trunk/modules/library/main/src/main/java/org/geotools/filter/visitor/SpatialFilterVisitor.java 2012-05-26 18:46:14 UTC (rev 38758) @@ -0,0 +1,111 @@ +/* + * GeoTools - The Open Source Java GIS Toolkit + * http://geotools.org + * + * (C) 2004-2008, Open Source Geospatial Foundation (OSGeo) + * + * 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; + * 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. + */ +package org.geotools.filter.visitor; + +import org.opengis.filter.spatial.BBOX; +import org.opengis.filter.spatial.Beyond; +import org.opengis.filter.spatial.Contains; +import org.opengis.filter.spatial.Crosses; +import org.opengis.filter.spatial.DWithin; +import org.opengis.filter.spatial.Disjoint; +import org.opengis.filter.spatial.Equals; +import org.opengis.filter.spatial.Intersects; +import org.opengis.filter.spatial.Overlaps; +import org.opengis.filter.spatial.Touches; +import org.opengis.filter.spatial.Within; + +/** + * Filter that can be applied to determine if a Filter contains any spatial filter + * + * @author Andrea Aime - GeoSolutions + * @since 2.7.5 + */ +public class SpatialFilterVisitor extends DefaultFilterVisitor { + + boolean hasSpatialFilter = false; + + /** + * True if the filter had a spatial filter, false otherwise + * @return + */ + public boolean hasSpatialFilter() { + return hasSpatialFilter; + } + + /** + * Resets this visitor so that it can be reused on another filter + */ + public void reset() { + hasSpatialFilter = false; + } + + public Object visit(final BBOX filter, Object data) { + hasSpatialFilter = true; + return data; + } + + public Object visit(Beyond filter, Object data) { + hasSpatialFilter = true; + return data; + } + + public Object visit(Contains filter, Object data) { + hasSpatialFilter = true; + return data; + } + + public Object visit(Crosses filter, Object data) { + hasSpatialFilter = true; + return data; + } + + public Object visit(Disjoint filter, Object data) { + hasSpatialFilter = true; + return data; + } + + public Object visit(DWithin filter, Object data) { + hasSpatialFilter = true; + return data; + } + + public Object visit(Equals filter, Object data) { + hasSpatialFilter = true; + return data; + } + + public Object visit(Intersects filter, Object data) { + hasSpatialFilter = true; + return data; + } + + public Object visit(Overlaps filter, Object data) { + hasSpatialFilter = true; + return data; + } + + public Object visit(Touches filter, Object data) { + hasSpatialFilter = true; + return data; + } + + public Object visit(Within filter, Object data) { + hasSpatialFilter = true; + return data; + } + +} Modified: trunk/modules/library/main/src/main/java/org/geotools/gml/producer/GeometryTransformer.java =================================================================== --- trunk/modules/library/main/src/main/java/org/geotools/gml/producer/GeometryTransformer.java 2012-05-25 08:10:24 UTC (rev 38757) +++ trunk/modules/library/main/src/main/java/org/geotools/gml/producer/GeometryTransformer.java 2012-05-26 18:46:14 UTC (rev 38758) @@ -22,7 +22,13 @@ */ package org.geotools.gml.producer; +import java.util.logging.Logger; + +import org.geotools.referencing.CRS; +import org.geotools.referencing.CRS.AxisOrder; +import org.geotools.util.logging.Logging; import org.geotools.xml.transform.TransformerBase; +import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.xml.sax.ContentHandler; import org.xml.sax.SAXException; import org.xml.sax.helpers.AttributesImpl; @@ -52,6 +58,8 @@ */ public class GeometryTransformer extends TransformerBase { + static final Logger LOGGER = Logging.getLogger(GeometryTransformer.class); + protected boolean useDummyZ = false; protected int numDecimals = 4; @@ -215,7 +223,24 @@ * Encodes the given geometry with no srsName attribute and forcing 2D */ public void encode(Geometry geometry) { - encode(geometry, null); + String srsName = null; + // see if we have a EPSG CRS attached to the geometry + if(geometry.getUserData() instanceof CoordinateReferenceSystem) { + try { + CoordinateReferenceSystem crs = (CoordinateReferenceSystem) geometry.getUserData(); + Integer code = CRS.lookupEpsgCode(crs, false); + if(code != null) { + if(AxisOrder.NORTH_EAST.equals(CRS.getAxisOrder(crs))) { + srsName = "urn:ogc:def:crs:EPSG::" + code; + } else { + srsName = "EPSG:" + code; + } + } + } catch(Exception e) { + LOGGER.fine("Failed to encode the CoordinateReferenceSystem into a srsName"); + } + } + encode(geometry, srsName); } /** Modified: trunk/modules/library/main/src/test/java/org/geotools/filter/DOMParserTest.java =================================================================== --- trunk/modules/library/main/src/test/java/org/geotools/filter/DOMParserTest.java 2012-05-25 08:10:24 UTC (rev 38757) +++ trunk/modules/library/main/src/test/java/org/geotools/filter/DOMParserTest.java 2012-05-26 18:46:14 UTC (rev 38758) @@ -28,6 +28,7 @@ import org.geotools.feature.SchemaException; import org.geotools.feature.simple.SimpleFeatureBuilder; import org.geotools.feature.simple.SimpleFeatureTypeBuilder; +import org.geotools.referencing.CRS; import org.geotools.test.TestData; import org.opengis.filter.Filter; import org.opengis.filter.PropertyIsNotEqualTo; @@ -36,6 +37,8 @@ import org.opengis.filter.spatial.Beyond; import org.opengis.filter.spatial.Crosses; import org.opengis.filter.spatial.DWithin; +import org.opengis.filter.spatial.Intersects; +import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; @@ -45,6 +48,7 @@ import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.LineString; import com.vividsolutions.jts.geom.Point; +import com.vividsolutions.jts.geom.Polygon; /** * Tests for the DOM parser. @@ -247,6 +251,17 @@ assertTrue(((Literal) cr.getExpression2()).getValue() instanceof LineString); LOGGER.fine("parsed filter is " + test); } + + public void testIntersectsCRS() throws Exception { + Filter test = parseDocument("intersectsCRS.xml"); + assertTrue(test instanceof Intersects); + Intersects cr = (Intersects) test; + assertEquals("geom", ((PropertyName) cr.getExpression1()).getPropertyName()); + Polygon p = (Polygon) ((Literal) cr.getExpression2()).getValue(); + assertTrue(p.getUserData() instanceof CoordinateReferenceSystem); + int epsg = CRS.lookupEpsgCode((CoordinateReferenceSystem) p.getUserData(), false); + assertEquals(32631, epsg); + } public void test28() throws Exception { FidFilter filter = (FidFilter) parseDocumentFirst("test28.xml"); Modified: trunk/modules/library/main/src/test/java/org/geotools/filter/FilterTransformerTest.java =================================================================== --- trunk/modules/library/main/src/test/java/org/geotools/filter/FilterTransformerTest.java 2012-05-25 08:10:24 UTC (rev 38757) +++ trunk/modules/library/main/src/test/java/org/geotools/filter/FilterTransformerTest.java 2012-05-26 18:46:14 UTC (rev 38758) @@ -16,47 +16,94 @@ */ package org.geotools.filter; +import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; +import java.util.Map; import junit.framework.TestCase; +import org.custommonkey.xmlunit.SimpleNamespaceContext; +import org.custommonkey.xmlunit.XMLAssert; +import org.custommonkey.xmlunit.XMLUnit; import org.geotools.factory.CommonFactoryFinder; +import org.geotools.referencing.CRS; import org.opengis.filter.Filter; import org.opengis.filter.FilterFactory2; import org.opengis.filter.identity.FeatureId; +import org.opengis.referencing.crs.CoordinateReferenceSystem; +import org.w3c.dom.Document; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.io.WKTReader; /** * - * + * * @source $URL$ */ public class FilterTransformerTest extends TestCase { FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2(null); + FilterTransformer transform = new FilterTransformer(); + + @Override + protected void setUp() throws Exception { + // init xmlunit + Map<String, String> namespaces = new HashMap<String, String>(); + namespaces.put("ogc", "http://www.opengis.net/ogc"); + namespaces.put("gml", "http://www.opengis.net/gml"); + namespaces.put("xsi", "http://www.w3.org/2001/XMLSchema-instance"); + + XMLUnit.setXpathNamespaceContext(new SimpleNamespaceContext(namespaces)); } public void testIdEncode() throws Exception { HashSet<FeatureId> set = new LinkedHashSet<FeatureId>(); - set.add( ff.featureId("FID.1")); - set.add( ff.featureId("FID.2")); - Filter filter=ff.id( set ); - - String output = transform.transform( filter ); - assertNotNull( "got xml", output ); + set.add(ff.featureId("FID.1")); + set.add(ff.featureId("FID.2")); + Filter filter = ff.id(set); + + String output = transform.transform(filter); + assertNotNull("got xml", output); String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><ogc:FeatureId xmlns=\"http://www.opengis.net/ogc\" xmlns:ogc=\"http://www.opengis.net/ogc\" xmlns:gml=\"http://www.opengis.net/gml\" fid=\"FID.1\"/><ogc:FeatureId fid=\"FID.2\"/>"; - assertEquals( "expected id filters", xml, output ); + assertEquals("expected id filters", xml, output); } - + public void testEncodeLong() throws Exception { Filter filter = ff.greater(ff.property("MYATT"), ff.literal(50000000l)); - String output = transform.transform( filter ); - assertNotNull( "got xml", output ); - String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><ogc:PropertyIsGreaterThan " + - "xmlns=\"http://www.opengis.net/ogc\" xmlns:ogc=\"http://www.opengis.net/ogc\" " + - "xmlns:gml=\"http://www.opengis.net/gml\">" + - "<ogc:PropertyName>MYATT</ogc:PropertyName>" + - "<ogc:Literal>50000000</ogc:Literal></ogc:PropertyIsGreaterThan>"; + String output = transform.transform(filter); + assertNotNull("got xml", output); + String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><ogc:PropertyIsGreaterThan " + + "xmlns=\"http://www.opengis.net/ogc\" xmlns:ogc=\"http://www.opengis.net/ogc\" " + + "xmlns:gml=\"http://www.opengis.net/gml\">" + + "<ogc:PropertyName>MYATT</ogc:PropertyName>" + + "<ogc:Literal>50000000</ogc:Literal></ogc:PropertyIsGreaterThan>"; assertEquals(xml, output); } + + public void testEncodeSRSNameLonLat() throws Exception { + // create a georeferenced geometry + CoordinateReferenceSystem wgs84 = CRS.decode("EPSG:4326", true); + Geometry point = new WKTReader().read("POINT(10 0)"); + point.setUserData(wgs84); + + // a filter on top of it + Filter filter = ff.overlaps(ff.property("geom"), ff.literal(point)); + String output = transform.transform(filter); + Document doc = XMLUnit.buildControlDocument(output); + XMLAssert.assertXpathEvaluatesTo("EPSG:4326", "//gml:Point/@srsName", doc); + } + + public void testEncodeSRSNameLatLon() throws Exception { + // create a georeferenced geometry + CoordinateReferenceSystem wgs84 = CRS.decode("urn:ogc:def:crs:EPSG::4326"); + Geometry point = new WKTReader().read("POINT(10 0)"); + point.setUserData(wgs84); + + // a filter on top of it + Filter filter = ff.overlaps(ff.property("geom"), ff.literal(point)); + String output = transform.transform(filter); + Document doc = XMLUnit.buildControlDocument(output); + XMLAssert.assertXpathEvaluatesTo("urn:ogc:def:crs:EPSG::4326", "//gml:Point/@srsName", doc); + } } Added: trunk/modules/library/main/src/test/java/org/geotools/filter/visitor/SpatialFilterVisitorTest.java =================================================================== --- trunk/modules/library/main/src/test/java/org/geotools/filter/visitor/SpatialFilterVisitorTest.java (rev 0) +++ trunk/modules/library/main/src/test/java/org/geotools/filter/visitor/SpatialFilterVisitorTest.java 2012-05-26 18:46:14 UTC (rev 38758) @@ -0,0 +1,53 @@ +package org.geotools.filter.visitor; + +import static org.junit.Assert.*; + +import org.geotools.factory.CommonFactoryFinder; +import org.junit.Before; +import org.junit.Test; +import org.opengis.filter.Filter; +import org.opengis.filter.FilterFactory2; + + +public class SpatialFilterVisitorTest { + + FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2(null); + private SpatialFilterVisitor visitor; + + + @Before + public void setUp() throws Exception { + visitor = new SpatialFilterVisitor(); + } + + @Test + public void testInclude() { + Filter.INCLUDE.accept(visitor, null); + assertFalse(visitor.hasSpatialFilter); + } + + @Test + public void testExclude() { + Filter.EXCLUDE.accept(visitor, null); + assertFalse(visitor.hasSpatialFilter); + } + + @Test + public void testBBOX() { + ff.bbox("geom", 0, 0, 10, 10, "EPSG:4326").accept(visitor, null); + assertTrue(visitor.hasSpatialFilter); + } + + @Test + public void testIntersects() { + ff.intersects(ff.property("geom"), ff.literal(null)).accept(visitor, null); + assertTrue(visitor.hasSpatialFilter); + } + + @Test + public void testOverlaps() { + ff.overlaps(ff.property("geom"), ff.literal(null)).accept(visitor, null); + assertTrue(visitor.hasSpatialFilter); + } + +} Added: trunk/modules/library/main/src/test/resources/org/geotools/filter/test-data/intersectsCRS.xml =================================================================== --- trunk/modules/library/main/src/test/resources/org/geotools/filter/test-data/intersectsCRS.xml (rev 0) +++ trunk/modules/library/main/src/test/resources/org/geotools/filter/test-data/intersectsCRS.xml 2012-05-26 18:46:14 UTC (rev 38758) @@ -0,0 +1,16 @@ +<Filter> + <Intersects> + <PropertyName>geom</PropertyName> + <gml:Polygon xmlns:gml="http://www.opengis.net/gml" + srsName="EPSG:32631"> + <gml:outerBoundaryIs> + <gml:LinearRing> + <gml:coordinates decimal="." cs="," ts=" ">278246.6541,552664.2969 + 500000,552664.2969 500000,774218.9664 + 278246.6541,774218.9664 278246.6541,552664.2969 + </gml:coordinates> + </gml:LinearRing> + </gml:outerBoundaryIs> + </gml:Polygon> + </Intersects> +</Filter> \ No newline at end of file Added: trunk/modules/library/render/src/test/java/org/geotools/renderer/lite/SpatialFilterTest.java =================================================================== --- trunk/modules/library/render/src/test/java/org/geotools/renderer/lite/SpatialFilterTest.java (rev 0) +++ trunk/modules/library/render/src/test/java/org/geotools/renderer/lite/SpatialFilterTest.java 2012-05-26 18:46:14 UTC (rev 38758) @@ -0,0 +1,84 @@ +package org.geotools.renderer.lite; + +import static org.junit.Assert.*; + +import java.io.File; +import java.util.HashSet; +import java.util.Set; + +import org.geotools.data.property.PropertyDataStore; +import org.geotools.data.simple.SimpleFeatureSource; +import org.geotools.factory.CommonFactoryFinder; +import org.geotools.geometry.jts.ReferencedEnvelope; +import org.geotools.map.FeatureLayer; +import org.geotools.map.MapContent; +import org.geotools.referencing.crs.DefaultGeographicCRS; +import org.geotools.renderer.RenderListener; +import org.geotools.styling.PolygonSymbolizer; +import org.geotools.styling.Rule; +import org.geotools.styling.Style; +import org.geotools.styling.StyleBuilder; +import org.geotools.test.TestData; +import org.junit.Before; +import org.opengis.feature.simple.SimpleFeature; +import org.opengis.filter.FilterFactory2; + +public class SpatialFilterTest { + + private static final long TIME = 2000; + + FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2(); + + SimpleFeatureSource squareFS; + + ReferencedEnvelope bounds; + + StreamingRenderer renderer; + + MapContent content; + + int errorCount = 0; + + Set<String> renderedIds = new HashSet<String>(); + + RenderListener listener; + + @Before + public void setUp() throws Exception { + // setup data + File property = new File(TestData.getResource(this, "square.properties").toURI()); + PropertyDataStore ds = new PropertyDataStore(property.getParentFile()); + squareFS = ds.getFeatureSource("square"); + bounds = new ReferencedEnvelope(0, 10, 0, 10, DefaultGeographicCRS.WGS84); + + // prepare the renderer + renderer = new StreamingRenderer(); + content = new MapContent(); + content.getViewport().setCoordinateReferenceSystem(DefaultGeographicCRS.WGS84); + + renderer.addRenderListener(new RenderListener() { + + public void featureRenderer(SimpleFeature feature) { + renderedIds.add(feature.getID()); + } + + public void errorOccurred(Exception e) { + errorCount++; + } + }); + } + + public void testSpatialNoReprojection() throws Exception { + // a spatial filter in the same SRS as the geometry + StyleBuilder sb = new StyleBuilder(); + PolygonSymbolizer ps = sb.createPolygonSymbolizer(); + Style style = sb.createStyle(ps); + Rule rule = style.featureTypeStyles().get(0).rules().get(0); + rule.setFilter(ff.bbox("geom", 1, 1, 4, 4, "EPSG:4326)")); + + content.addLayer(new FeatureLayer(squareFS, style)); + + RendererBaseTest.showRender("OneSquare", renderer, TIME, bounds); + assertEquals(2, renderedIds.size()); + } +} |
From: <svn...@os...> - 2012-05-25 08:10:38
|
Author: ang05a Date: 2012-05-25 01:10:24 -0700 (Fri, 25 May 2012) New Revision: 38757 Removed: trunk/docs/user/artifacts/config Modified: trunk/docs/user/advanced/build/install/svn.rst Log: Fix previous commit with svn.rst: - remove byte order mark - remove stale svn config file Modified: trunk/docs/user/advanced/build/install/svn.rst =================================================================== --- trunk/docs/user/advanced/build/install/svn.rst 2012-05-25 05:38:10 UTC (rev 38756) +++ trunk/docs/user/advanced/build/install/svn.rst 2012-05-25 08:10:24 UTC (rev 38757) @@ -1,4 +1,4 @@ -Subversion Install +Subversion Install ------------------ Subversion is an advanced version management tool with the same command line syntax as CVS. @@ -19,7 +19,7 @@ Please note that whatever client you use; we need to ask you to configure subversion correctly to work with our repository. -1. Copy :download:`config<../../../../../build/subversion/config>` +1. Copy :download:`config</../../build/subversion/config>` 2. Into the following location ============= =========================================================================== Deleted: trunk/docs/user/artifacts/config =================================================================== --- trunk/docs/user/artifacts/config 2012-05-25 05:38:10 UTC (rev 38756) +++ trunk/docs/user/artifacts/config 2012-05-25 08:10:24 UTC (rev 38757) @@ -1,122 +0,0 @@ -### This file configures various client-side behaviors. -### -### The commented-out examples below are intended to demonstrate -### how to use this file. - -### Section for authentication and authorization customizations. -### Set store-auth-creds to 'no' to avoid storing your subversion -### credentials in the auth/ area of your config directory. -### It defaults to 'yes'. Note that this option only prevents -### saving of *new* credentials; it doesn't invalidate existing -### caches. (To do that, remove the cache files by hand.) -# [auth] -# store-auth-creds = no - -### Section for configuring external helper applications. -### Set editor to the command used to invoke your text editor. -### This will override the environment variables that Subversion -### examines by default to find this information ($EDITOR, -### et al). -### Set diff-cmd to the absolute path of your 'diff' program. -### This will override the compile-time default, which is to use -### Subversion's internal diff implementation. -### Set diff3-cmd to the absolute path of your 'diff3' program. -### This will override the compile-time default, which is to use -### Subversion's internal diff3 implementation. -### Set diff3-has-program-arg to 'true' or 'yes' if your 'diff3' -### program accepts the '--diff-program' option. -# [helpers] -# editor-cmd = editor (vi, emacs, notepad, etc.) -# diff-cmd = diff_program (diff, gdiff, etc.) -# diff3-cmd = diff3_program (diff3, gdiff3, etc.) -# diff3-has-program-arg = [true | false] - -### Section for configuring tunnel agents. -# [tunnels] -### Configure svn protocol tunnel schemes here. By default, only -### the 'ssh' scheme is defined. You can define other schemes to -### be used with 'svn+scheme://hostname/path' URLs. A scheme -### definition is simply a command, optionally prefixed by an -### environment variable name which can override the command if it -### is defined. The command (or environment variable) may contain -### arguments, using standard shell quoting for arguments with -### spaces. The command will be invoked as: -### <command> <hostname> svnserve -t -### (If the URL includes a username, then the hostname will be -### passed to the tunnel agent as <user>@<hostname>.) If the -### built-in ssh scheme were not predefined, it could be defined -### as: -# ssh = $SVN_SSH ssh -### If you wanted to define a new 'rsh' scheme, to be used with -### 'svn+rsh:' URLs, you could do so as follows: -# rsh = rsh -### Or, if you wanted to specify a full path and arguments: -# rsh = /path/to/rsh -l myusername -### On Windows, if you are specifying a full path to a command, -### use a forward slash (/) or a paired backslash (\\) as the -### path separator. A single backslash will be treated as an -### escape for the following character. - -### Section for configuring miscelleneous Subversion options. -[miscellany] -### Set global-ignores to a set of whitespace-delimited globs -### which Subversion will ignore in its 'status' output. - -global-ignores = *.o *.lo *.la #*# .*.rej *.rej .*~ *~ .#* *.class - -### Set log-encoding to the default encoding for log messages -# log-encoding = latin1 -### Set use-commit-times to make checkout/update/switch/revert -### put last-committed timestamps on every file touched. -# use-commit-times = yes -### Set enable-auto-props to 'yes' to enable automatic properties -### for 'svn add' and 'svn import', it defaults to 'no'. -### Automatic properties are defined in the section 'auto-props'. - -enable-auto-props = yes - -### Section for configuring automatic properties. -### The format of the entries is: -### file-name-pattern = propname[=value][;propname[=value]...] -### The file-name-pattern can contain wildcards (such as '*' and -### '?'). All entries which match will be applied to the file. -### Note that auto-props functionality must be enabled, which -### is typically done by setting the 'enable-auto-props' option. -[auto-props] -*.java = svn:mime-type=text/plain;svn:eol-style=native;svn:keywords=Id -*.sql = svn:mime-type=text/plain;svn:eol-style=native;svn:keywords=Id -*.c = svn:mime-type=text/plain;svn:eol-style=native;svn:keywords=Id -*.cpp = svn:mime-type=text/plain;svn:eol-style=native;svn:keywords=Id -*.h = svn:mime-type=text/plain;svn:eol-style=native;svn:keywords=Id -*.txt = svn:mime-type=text/plain;svn:eol-style=native;svn:keywords=Id -*.sgml = svn:mime-type=text/plain;svn:eol-style=native;svn:keywords=Id -*.properties = svn:mime-type=text/plain;svn:eol-style=native;svn:keywords=Id -*.xml = svn:mime-type=text/xml;svn:eol-style=native;svn:keywords=Id -*.classpath = svn:mime-type=text/xml;svn:eol-style=native;svn:keywords=Id -*.project = svn:mime-type=text/xml;svn:eol-style=native;svn:keywords=Id -*.sld = svn:mime-type=text/xml;svn:eol-style=native;svn:keywords=Id -*.gml = svn:mime-type=text/xml;svn:eol-style=native;svn:keywords=Id -*.xsl = svn:mime-type=text/xsl;svn:eol-style=native;svn:keywords=Id -*.html = svn:mime-type=text/html;svn:eol-style=native;svn:keywords=Id -*.css = svn:mime-type=text/css;svn:eol-style=native;svn:keywords=Id -*.dsp = svn:eol-style=CRLF -*.bat = svn:eol-style=CRLF -*.dsw = svn:eol-style=CRLF -*.sh = svn:eol-style=native;svn:executable;svn:keywords=Id -*.png = svn:mime-type=image/png -*.jpg = svn:mime-type=image/jpeg -*.gif = svn:mime-type=image/gif -*.tif = svn:mime-type=image/tiff -*.zip = svn:mime-type=application/zip -*.sxw = svn:mime-type=application/zip -*.sxc = svn:mime-type=application/zip -*.sxi = svn:mime-type=application/zip -*.utf = svn:mime-type=application/octet-stream -*.ttf = svn:mime-type=application/octet-stream -*.shp = svn:mime-type=application/octet-stream -*.shx = svn:mime-type=application/octet-stream -*.dbf = svn:mime-type=application/octet-stream -*.mif = svn:mime-type=application/octet-stream -*.mid = svn:mime-type=application/octet-stream -Makefile = svn:mime-type=text/plain;svn:eol-style=native -README = svn:mime-type=text/plain;svn:eol-style=native \ No newline at end of file |
From: <svn...@os...> - 2012-05-25 05:38:17
|
Author: ang05a Date: 2012-05-24 22:38:10 -0700 (Thu, 24 May 2012) New Revision: 38756 Modified: trunk/docs/user/advanced/build/install/svn.rst Log: Fix svn config path to point to build/subversion/config file. Modified: trunk/docs/user/advanced/build/install/svn.rst =================================================================== --- trunk/docs/user/advanced/build/install/svn.rst 2012-05-25 04:38:31 UTC (rev 38755) +++ trunk/docs/user/advanced/build/install/svn.rst 2012-05-25 05:38:10 UTC (rev 38756) @@ -1,4 +1,4 @@ -Subversion Install +Subversion Install ------------------ Subversion is an advanced version management tool with the same command line syntax as CVS. @@ -19,7 +19,7 @@ Please note that whatever client you use; we need to ask you to configure subversion correctly to work with our repository. -1. Copy :download:`config</artifacts/config>` +1. Copy :download:`config<../../../../../build/subversion/config>` 2. Into the following location ============= =========================================================================== |
From: <nit...@gm...> - 2012-05-25 05:35:05
|
ทักษิณ ทิ้ง ชูพงศ์ หนีกลับบ้าน หลายคนที่ได้ฟังได้อ่านคำปราศรัยของคุณทักษิณ เมื่อวันที่ 19 พฤษภาคม 2555 แล้วคงต้องตีความกันอีกนาน โดยเฉพาะคนเสื้อแดงว่า ความต้องการที่แท้จริงของคุณทักษิณคืออะไร แต่ที่แน่ๆ ชูพงศ์ ถี่ถ้วน คง ได้รับคำตอบที่ชัดเจนมานานแล้ว เพียงแต่เก็บอาการไว้เท่านั้นเอง คงจำได้ ว่าเมื่อเทศกาลวันงสกรานต์ คุณทักษิณมาร่วมงานกับพี่น้องคนเสื้อแดงที่ ประเทศลาวและกัมพูชา ชูพงศ์ได้กล่าวว่าการเคลื่อนไหวของคุณทักษิณใน ประเทศเพื่อนบ้านนั้นเป็นการตอกย้ำว่าคุณทักษิณไม่ได้ทิ้งคนเสื้อแดง และ ยังได้แสดงถึงการให้กำลังใจให้ต่อสู้ต่อไป ชูพงศ์กล่าวว่าจะเข้าพบกับคุณ ทักษิณที่กัมพูชาในวันที่ 17 เมษายน 2555 แต่ข่าววงในรายงานว่าทักษิณ ไม่ให้เข้าพบ ชูพงศ์ก็ออกอาการเป๋ๆ จัดรายการวิทยุพูดจาวกไปวนมา ทำ ตัวเป็นทองไม่รู้ร้อน และต้องตกใจตื่นเมื่อวันที่ 19 พฤษภาคม นี้เองว่าพวก เสื้อแดงไม่เอาสถาบันถูกทิ้งแล้ว คงต้องกับไปหากินกับเงินบริจาคของ ชาวบ้านร่วมกับ ดร.ริชาร์ด ไสโสมอน เจ้าของเวบไซต์ ITF (internetofreedom.com) อีกเช่นเคย ถ้าจะอ้างอาการป่วยอีกก็ต้องบอก ด้วยว่า “ป่วยใจถูกเขี่ยทิ้ง” ไม่ใช่เพียงชูพงศ์เท่านั้นที่ไม่ต้องการให้คุณ ทักษิณกลับบ้าน มีเหลือบไรเห็บเหาอีกเยอะมากที่ต้องการเงินของคุณ ทักษิณ อ้างว่านำมาใช้ในการเคลื่อนไหว แต่คุณทักษิณก็ได้ลงทุนไปมาก แล้ว น้องสาวได้เป็นนายกรัฐมนตรี เสื้อแดง นปช. ก็ได้เป็นอำมาตย์หลาย ตำแหน่ง การเรียกร้องของคุณทักษิณเพื่อการปรองดอง คนเสื้อแดงต้อง เสียสละ กลับมาปกป้องชาติ ศาสนาและพระมหากษัตริย์ เป็นเรื่องที่ถูกต้อง แล้ว ให้คุณทักษิณได้กลับบ้านเถอะ อย่าได้ให้ร้ายคุณทักษิณเขาอีกเลยนะ ชูพงศ์ ถี่ถ้วน จาก... บรรพต |
Author: jive Date: 2012-05-24 21:38:31 -0700 (Thu, 24 May 2012) New Revision: 38755 Modified: trunk/modules/library/main/src/main/java/org/geotools/data/DataUtilities.java trunk/modules/library/main/src/test/java/org/geotools/data/DataUtilitiesTest.java trunk/modules/plugin/property/src/main/java/org/geotools/data/property/PropertyAttributeReader.java Log: Port createFeature and encodeFeature methods from PropertyDataStore internals to public DataUtilities methods Signed-off-by: Jody Garnett <jod...@gm...> Modified: trunk/modules/library/main/src/main/java/org/geotools/data/DataUtilities.java =================================================================== --- trunk/modules/library/main/src/main/java/org/geotools/data/DataUtilities.java 2012-05-25 04:38:04 UTC (rev 38754) +++ trunk/modules/library/main/src/main/java/org/geotools/data/DataUtilities.java 2012-05-25 04:38:31 UTC (rev 38755) @@ -83,6 +83,7 @@ import org.geotools.filter.FilterAttributeExtractor; import org.geotools.filter.visitor.PropertyNameResolvingVisitor; import org.geotools.geometry.jts.ReferencedEnvelope; +import org.geotools.geometry.jts.WKTReader2; import org.geotools.metadata.iso.citation.Citations; import org.geotools.referencing.CRS; import org.geotools.resources.i18n.ErrorKeys; @@ -110,6 +111,8 @@ import org.opengis.filter.expression.PropertyName; import org.opengis.filter.sort.SortBy; import org.opengis.geometry.BoundingBox; +import org.opengis.metadata.citation.Citation; +import org.opengis.referencing.FactoryException; import org.opengis.referencing.ReferenceIdentifier; import org.opengis.referencing.crs.CoordinateReferenceSystem; @@ -1857,32 +1860,6 @@ return builder.buildFeatureType(); } - - - /** - * Uses {@link Converters} to parse the provided text into the correct values to create a feature. - * - * @param type - * FeatureType - * @param fid - * Feature ID for new feature - * @param text - * Text representation of values - * - * @return newly created feature - * @throws IllegalAttributeException - */ - public static SimpleFeature parse(SimpleFeatureType type, String fid, String[] text) - throws IllegalAttributeException { - Object[] attributes = new Object[text.length]; - - for (int i = 0; i < text.length; i++) { - AttributeType attType = type.getDescriptor(i).getType(); - attributes[i] = Converters.convert(text[i], attType.getBinding()); - } - - return SimpleFeatureBuilder.build(type, attributes, fid); - } // // Encoding support for PropertyFeatureWriter // @@ -1899,10 +1876,55 @@ * @param featureType * @return String representation of featureType suitable for use with {@link #createType} */ - public static String encodeType( FeatureType featureType ){ - return spec(featureType); + public static String encodeType(SimpleFeatureType featureType) { + Collection<PropertyDescriptor> types = featureType.getDescriptors(); + StringBuffer buf = new StringBuffer(); + + for (PropertyDescriptor type : types) { + buf.append(type.getName().getLocalPart()); + buf.append(":"); + buf.append(typeMap(type.getType().getBinding())); + if (type instanceof GeometryDescriptor) { + GeometryDescriptor gd = (GeometryDescriptor) type; + int srid = toSRID( gd.getCoordinateReferenceSystem() ); + if( srid != -1 ){ + buf.append(":srid=" + srid); + } + } + buf.append(","); + } + buf.delete(buf.length() - 1, buf.length()); // remove last "," + return buf.toString(); } /** + * Quickly review provided crs checking for an "EPSG:SRID" reference identifier. + * <p> + * @see CRS#lookupEpsgCode(CoordinateReferenceSystem, boolean) for full search + * @param crs + * @return srid or -1 if not found + */ + private static int toSRID( CoordinateReferenceSystem crs ){ + if (crs == null || crs.getIdentifiers() == null) { + return -1; // not found + } + for (Iterator<ReferenceIdentifier> it = crs.getIdentifiers().iterator(); it + .hasNext();) { + ReferenceIdentifier id = it.next(); + Citation authority = id.getAuthority(); + if (authority != null + && authority.getTitle().equals(Citations.EPSG.getTitle())) { + try { + return Integer.parseInt( id.getCode() ); + } + catch (NumberFormatException nanException ){ + continue; + } + } + } + return -1; + } + + /** * A "quick" String representation of a FeatureType. * <p> * This string representation may be used with createType( name, spec ). @@ -1912,6 +1934,7 @@ * FeatureType to represent * * @return The string "specification" for the featureType + * @deprecated Renamed to {@link #encodeType} for concistency with {@link #createType} */ public static String spec(FeatureType featureType) { Collection<PropertyDescriptor> types = featureType.getDescriptors(); @@ -1941,10 +1964,267 @@ buf.append(","); } buf.delete(buf.length() - 1, buf.length()); // remove last "," - return buf.toString(); } /** + * Reads in SimpleFeature that has been encoded into a line of text. + * <p> + * Example:<pre> + * SimpleFeatureType featureType = + * DataUtilities.createType("FLAG","id:Integer|name:String|geom:Geometry:4326"); + * + * SimpleFeature feature = + * DataUtilities.createFeature( featureType, "fid1=1|Jody Garnett\\nSteering Committee|POINT(1,2)" ); + * </pre> + * This format is used by the PropertyDataStore tutorials. It amounts to: + * <ul> + * <li> + * <li>Encoding of <i>FeatureId</i> followed by the attributes</li> + * <li>Attributes are seperated using the bar character</li> + * <li>Geometry is handled using {@link WKTReader2}</li> + * <li>Support for common escaped characters</li> + * <li>Multi-line support using escaped line-feed characters</li> + * <ul> + * @param featureType + * @param line + * @return SimpleFeature defined by the provided line of text + */ + public static SimpleFeature createFeature( SimpleFeatureType featureType, String line ){ + String fid; + + int fidSplit = line.indexOf('='); + int barSplit = line.indexOf('|'); + if( fidSplit == -1 || (barSplit != -1 && barSplit < fidSplit) ){ + fid = null; // we need to generate a feature id + } + else { + fid = line.substring(0, fidSplit); + } + String data = line.substring(fidSplit+1); + String text[] = splitIntoText(data, featureType ); + Object[] values = new Object[ text.length ]; + for( int i=0; i<text.length;i++){ + AttributeDescriptor descriptor = featureType.getDescriptor(i); + Object value = createValue( descriptor, text[i] ); + values[i] = value; + } + SimpleFeature feature = SimpleFeatureBuilder.build( featureType, values, fid ); + + return feature; + } + + /** + * Split the provided text using | charater as a seperator. + * <p> + * This method respects the used of \ to "escape" a | character allowing + * representations such as the following:<pre> + * String example="text|example of escaped \\| character|text"; + * + * // represents: "text|example of escaped \| character|text" + * String split=splitIntoText( example );</pre> + * + * @param data Origional raw text as stored + * @return data split using | as seperator + * @throws DataSourceException if the information stored is inconsistent with the headered provided + */ + private static String[] splitIntoText(String data,SimpleFeatureType type) { + // return data.split("|", -1); // use -1 as a limit to include empty trailing spaces + // return data.split("[.-^\\\\]\\|",-1); //use -1 as limit to include empty trailing spaces + + String text[] = new String[type.getAttributeCount()]; + int i = 0; + StringBuilder item = new StringBuilder(); + for (String str : data.split("\\|",-1)) { + if (i == type.getAttributeCount()) { + // limit reached + throw new IllegalArgumentException("format error: expected " + text.length + + " attributes, stopped after finding " + i + ". [" + data + + "] split into " + Arrays.asList(text)); + } + if (str.endsWith("\\")) { + item.append(str); + item.append("|"); + } else { + item.append(str); + text[i] = item.toString(); + i++; + item = new StringBuilder(); + } + } + if (i < type.getAttributeCount()) { + throw new IllegalArgumentException("createFeature format error: expected " + type.getAttributeCount() + + " attributes, but only found " + i + ". [" + data + "] split into " + + Arrays.asList(text)); + } + return text; + } + /** + * Reads an attribute value out of the raw text supplied to {@link #createFeature}. + * <p> + * This method is responsible for: + * <ul> + * <li>Handling: <code>"<null>"</code> as an explicit marker flag for a null value</li> + * <li>Using {@link #decodeEscapedCharacters(String)} to unpack the raw text</li> + * <li>Using {@link Converters} to convert the text to the requested value</li> + * @param descriptor + * @param rawText + * @return + */ + private static Object createValue(AttributeDescriptor descriptor, String rawText) { + String stringValue = null; + try { + // read the value and decode any interesting characters + stringValue = decodeEscapedCharacters(rawText); + } catch (RuntimeException huh) { + huh.printStackTrace(); + stringValue = null; + } + // check for special <null> flag + if ("<null>".equals(stringValue)) { + stringValue = null; + } + if (stringValue == null) { + if (descriptor.isNillable()) { + return null; // it was an explicit "<null>" + } + } + // Use of Converters to convert from String to requested java binding + Object value = Converters.convert(stringValue, descriptor.getType().getBinding()); + + if (descriptor.getType() instanceof GeometryType) { + // this is to be passed on in the geometry objects so the srs name gets encoded + CoordinateReferenceSystem crs = ((GeometryType) descriptor.getType()) + .getCoordinateReferenceSystem(); + if (crs != null) { + // must be geometry, but check anyway + if (value != null && value instanceof Geometry) { + ((Geometry) value).setUserData(crs); + } + } + } + return value; + } + /** + * Produce a String encoding of SimpleFeature for use with {@link #createFeature}. + * <p> + * This method inlcudes the full featureId information. + * @param feature feature to encode, only SimpleFeature is supported at this time + * @return text encoding for use with {@link #createFeature} + */ + public static String encodeFeature(SimpleFeature feature){ + return encodeFeature(feature, true ); + } + /** + * Produce a String encoding of SimpleFeature for use with {@link #createFeature}. + * <p> + * This method inlcudes the full featureId information. + * @param feature feature to encode, only SimpleFeature is supported at this time + * @param includeFid true to include the optional feature id + * @return text encoding for use with {@link #createFeature} + */ + public static String encodeFeature(SimpleFeature feature,boolean includeFid ){ + StringBuilder build = new StringBuilder(); + if( includeFid ){ + String fid = feature.getID(); + if( feature.getUserData().containsKey(Hints.PROVIDED_FID)){ + fid = (String) feature.getUserData().get(Hints.PROVIDED_FID); + } + build.append(fid); + build.append("="); + } + for (int i = 0; i < feature.getAttributeCount(); i++) { + Object attribute = feature.getAttribute(i); + if( i != 0 ){ + build.append("|"); // seperator character + } + if (attribute == null) { + build.append("<null>"); // nothing! + } else if( attribute instanceof String){ + String txt = encodeString((String) attribute); + build.append( txt ); + } else if (attribute instanceof Geometry) { + Geometry geometry = (Geometry) attribute; + String txt = geometry.toText(); + + txt = encodeString( txt ); + build.append( txt ); + } else { + String txt = Converters.convert( attribute, String.class ); + if( txt == null ){ // could not convert? + txt = attribute.toString(); + } + txt = encodeString( txt ); + build.append( txt ); + } + } + return build.toString(); + } + + /** + * Uses {@link Converters} to parse the provided text into the correct values to create a feature. + * + * @param type + * FeatureType + * @param fid + * Feature ID for new feature + * @param text + * Text representation of values + * + * @return newly created feature + * @throws IllegalAttributeException + */ + public static SimpleFeature parse(SimpleFeatureType type, String fid, String[] text) + throws IllegalAttributeException { + Object[] attributes = new Object[text.length]; + + for (int i = 0; i < text.length; i++) { + AttributeType attType = type.getDescriptor(i).getType(); + attributes[i] = Converters.convert(text[i], attType.getBinding()); + } + return SimpleFeatureBuilder.build(type, attributes, fid); + } + + // + // Internal utility methods to support PropertyDataStore feature encoding / decoding + // + /** + * Used to decode common whitespace chracters and escaped | characters. + * + * @param txt Origional raw text as stored + * @return decoded text as provided for storage + * @see PropertyAttributeWriter#encodeString(String) + */ + private static String decodeEscapedCharacters( String txt ){ + // unpack whitespace constants + txt = txt.replace( "\\n", "\n"); + txt = txt.replaceAll("\\r", "\r" ); + + // unpack our our escaped characters + txt = txt.replace("\\|", "|" ); + // txt = txt.replace("\\\\", "\\" ); + + return txt; + } + + /** + * Used to encode common whitespace characters and | character for safe transport. + * + * @param txt + * @return txt encoded for storage + * @see PropertyAttributeReader#decodeString(String) + */ + private static String encodeString( String txt ){ + // encode our escaped characters + // txt = txt.replace("\\", "\\\\"); + txt = txt.replace("|","\\|"); + + // encode whitespace constants + txt = txt.replace("\n", "\\n"); + txt = txt.replace("\r", "\\r"); + + return txt; + } + /** * Internal method to access java binding using readable typename. * @see #createType(String, String) */ @@ -1962,16 +2242,11 @@ if (typeEncode.containsKey(type)) { return typeEncode.get(type); } - /* - * SortedSet<String> choose = new TreeSet<String>(); for (Iterator i = - * typeMap.entrySet().iterator(); i.hasNext();) { Map.Entry entry = (Entry) i.next(); - * - * if (entry.getValue().equals(type)) { choose.add( (String) entry.getKey() ); } } if( - * !choose.isEmpty() ){ return choose.last(); } - */ return type.getName(); } - + // + // Query Support Methods for DataStore implementators + // /** * Factory method to produce Comparator based on provided Query SortBy information. * <p> Modified: trunk/modules/library/main/src/test/java/org/geotools/data/DataUtilitiesTest.java =================================================================== --- trunk/modules/library/main/src/test/java/org/geotools/data/DataUtilitiesTest.java 2012-05-25 04:38:04 UTC (rev 38754) +++ trunk/modules/library/main/src/test/java/org/geotools/data/DataUtilitiesTest.java 2012-05-25 04:38:31 UTC (rev 38755) @@ -447,7 +447,39 @@ assertEquals(rv1.getAttribute("flow"), rv3.getAttribute("flow")); assertNull(rv3.getDefaultGeometry()); } + /** + * Test createType and createFeature methods as per GEOT-4150 + */ + public void testCreate() throws Exception { + SimpleFeatureType featureType = DataUtilities.createType("Contact","id:Integer,party:String,geom:Geometry:srid=4326"); + SimpleFeature feature1 = DataUtilities.createFeature( featureType, "fid1=1|Jody Garnett\\nSteering Committee|POINT(1 2)" ); + SimpleFeature feature2 = DataUtilities.createFeature( featureType, "2|John Hudson\\|Hapless Victim|POINT(6 2)" ); + assertNotNull( featureType.getCoordinateReferenceSystem() ); + + Geometry geometry = (Geometry)feature1.getAttribute("geom"); + assertEquals( "geom", 2.0, geometry.getCoordinate().y ); + assertEquals( "fid preservation", "fid1", feature1.getID() ); + + // test escape handling + assertEquals( "newline decode check", "Jody Garnett\nSteering Committee", feature1.getAttribute("party") ); + assertEquals( "escape check", "John Hudson|Hapless Victim", feature2.getAttribute("party") ); + } + /** + * Test createType and createFeature methods as per GEOT-4150 + */ + + public void testEncode() throws Exception { + SimpleFeatureType featureType = DataUtilities.createType("Contact","id:Integer,party:String,geom:Geometry:srid=4326"); + SimpleFeature feature1 = DataUtilities.createFeature( featureType, "fid1=1|Jody Garnett\\nSteering Committee|POINT (1 2)" ); + SimpleFeature feature2 = DataUtilities.createFeature( featureType, "2|John Hudson\\|Hapless Victim|POINT (6 2)" ); + + String spec = DataUtilities.encodeType(featureType); + assertEquals("id:Integer,party:String,geom:Geometry:srid=4326", spec ); + + String text = DataUtilities.encodeFeature(feature1); + assertEquals( "fid1=1|Jody Garnett\\nSteering Committee|POINT (1 2)", text ); + } /* * Test for Feature template(FeatureType) */ Modified: trunk/modules/plugin/property/src/main/java/org/geotools/data/property/PropertyAttributeReader.java =================================================================== --- trunk/modules/plugin/property/src/main/java/org/geotools/data/property/PropertyAttributeReader.java 2012-05-25 04:38:04 UTC (rev 38754) +++ trunk/modules/plugin/property/src/main/java/org/geotools/data/property/PropertyAttributeReader.java 2012-05-25 04:38:31 UTC (rev 38755) @@ -184,6 +184,13 @@ next = readLine(); return next != null; } + /** + * Read the next line of content, paying careful attention to skip comments and for correct + * handling of lines that end with escaped line-feeds to span multi lines in the text file. + * + * @return + * @throws IOException + */ String readLine() throws IOException { StringBuilder buffer = new StringBuilder(); while( true ){ @@ -213,8 +220,6 @@ return null; // there is no line } String raw = buffer.toString(); -// String line = decodeString(raw); -// return line; return raw; } /** @@ -301,9 +306,9 @@ for (String str : data.split("\\|",-1)) { if (i == type.getAttributeCount()) { // limit reached - throw new DataSourceException("format error: expected " + text.length - + " attributes, stopped after finding " + i + ". [" + line - + "] split into " + Arrays.asList(text)); + throw new DataSourceException("format error: expected " + split.length + + " attributes, stopped after finding " + i + ". [" + data + + "] split into " + Arrays.asList(split)); } if (str.endsWith("\\")) { // String shorter = str.substring(0, str.length() - 1); @@ -320,8 +325,8 @@ } if (i < type.getAttributeCount()) { throw new DataSourceException("format error: expected " + type.getAttributeCount() - + " attributes, but only found " + i + ". [" + line + "] split into " - + Arrays.asList(text)); + + " attributes, but only found " + i + ". [" + data + "] split into " + + Arrays.asList(split)); } return split; } |
From: <svn...@os...> - 2012-05-25 04:38:11
|
Author: jive Date: 2012-05-24 21:38:04 -0700 (Thu, 24 May 2012) New Revision: 38754 Modified: trunk/modules/library/referencing/src/main/java/org/geotools/referencing/CRS.java Log: Added a null check in case AbstractAuthorityFactory comes back null Signed-off-by: Jody Garnett <jod...@gm...> Modified: trunk/modules/library/referencing/src/main/java/org/geotools/referencing/CRS.java =================================================================== --- trunk/modules/library/referencing/src/main/java/org/geotools/referencing/CRS.java 2012-05-24 11:20:49 UTC (rev 38753) +++ trunk/modules/library/referencing/src/main/java/org/geotools/referencing/CRS.java 2012-05-25 04:38:04 UTC (rev 38754) @@ -1034,7 +1034,7 @@ if (!Citations.identifierMatches(factory.getAuthority(), authority)) { continue; } - if (!(factory instanceof AbstractAuthorityFactory)) { + if (factory == null || !(factory instanceof AbstractAuthorityFactory)) { continue; } final AbstractAuthorityFactory f = (AbstractAuthorityFactory) factory; |
From: <svn...@os...> - 2012-05-24 11:21:00
|
Author: jive Date: 2012-05-24 04:20:49 -0700 (Thu, 24 May 2012) New Revision: 38753 Modified: trunk/modules/library/main/src/main/java/org/geotools/data/DataUtilities.java Log: Work on the class javadoc Signed-off-by: Jody Garnett <jod...@gm...> Modified: trunk/modules/library/main/src/main/java/org/geotools/data/DataUtilities.java =================================================================== --- trunk/modules/library/main/src/main/java/org/geotools/data/DataUtilities.java 2012-05-24 09:16:41 UTC (rev 38752) +++ trunk/modules/library/main/src/main/java/org/geotools/data/DataUtilities.java 2012-05-24 11:20:49 UTC (rev 38753) @@ -17,6 +17,7 @@ package org.geotools.data; import java.io.File; +import java.io.FileFilter; import java.io.FilenameFilter; import java.io.IOException; import java.io.UnsupportedEncodingException; @@ -127,17 +128,60 @@ import org.geotools.data.view.DefaultView; /** - * Utility functions for use when implementing working with data classes. + * Utility functions for use with GeoTools with data classes. * <p> - * TODO: Move FeatureType manipulation to feature package + * These methods fall into several categories: + * <p> + * Conversion between common data structures. + * <ul> + * <li>{@link #collection} methods: creating/converting a {@link SimpleFeatureCollection} from a range of input.</li> + * <li>{@link #simple} methods: adapting from generic Feature use to SimpleFeature. Used to convert to SimpleFeature, + * SimpleFeatureCollection,SimpleFeatureSource</li> + * <li>{@link #list} to quickly copy features into a memory based list</li> + * <li>{@link #reader} methods to convert to FeatureReader</li> + * <li>{@link #source} setup a FeatureSource wrapper around the provided data</li> + * </ul> * </p> + * <p> + * SimpleFeatureType and SimpleFeature encoding/decoding from String as used by the PropertyDataStore tutorials. + * <ul> + * <li>{@link #createType} methods: to create a SimpleFeatureType from a one line text string</li> + * <li>{@link #encodeType}: text string representation of a SimpleFeaturerType</li> + * <li>{@link #createFeature}: create a SimpleFeature from a one line text String</li> + * <li>{@link #encodeFeature}: encode a feature as a single line text string</li> + * </ul> + * </p> + * <p> + * Working with SimpleFeatureType (this class is immutable so we always have to make a modified copy): + * <ul> + * <li>{@link #createSubType(SimpleFeatureType, String[])} methods return a modified copy of an origional feature type. Used to cut down an exsiting + * feature type to reflect only the attributes requested when using {@link SimpleFeatureSource#getFeatures(Filter)}.</li> + * <li>{@link #compare} and {@link #isMatch(AttributeDescriptor, AttributeDescriptor)} are used to check for types compatible with + * {@link #createSubType} used to verify that feature values can be copied across</li> + * </ul> + * </p> + * <p> + * Manipulating individual features and data values: + * <ul> + * <li>{@link #reType} generates a cut down version of an original feature in the same manners as {@link #createSubType}</li> + * <li>{@link #template} and {@link #defaultValue} methods which uses {@link AttributeDescriptor#getDefaultValue()} when creating new empty features</li> + * <li>{@link #duplicate(Object)} used for deep copy of feature data</li> + * <li> + * </ul> + * </p> + * And a grab bag of helpful utility methods for those implementing a DataStore: + * <ul> + * <li>{@link #urlToFile(URL)} and {@link #fileToURL(File)} and {@link #getParentUrl(URL)} used to work with files across platforms</li> + * <li>{@link #includeFilters} and {@link #excludeFilters} work as a compound {@link FileFilter} making {@link File#listFiles} easier to use</li> + * <li>{@link #propertyNames}, {@link #fidSet}, {@link #attributeNames} methods are used to double check a provided query and ensure + * it can be correctly handed.</li> + * </li>{@link #sortComparator}, {@link #resolvePropertyNames} and {@link #mixQueries} are used to prep a {@link Query} prior to use</li> + * </ul> * * @author Jody Garnett, Refractions Research - * - * - * @source $URL$ - * http://svn.osgeo.org/geotools/trunk/modules/library/main/src/main/java/org/geotools/ - * data/DataUtilities.java $ + * + * + * @source $URL$ http://svn.osgeo.org/geotools/trunk/modules/library/main/src/main/java/org/geotools/ data/DataUtilities.java $ */ public class DataUtilities { /** Typemap used by {@link #createType(String, String)} methods */ |
From: <svn...@os...> - 2012-05-24 09:16:49
|
Author: jive Date: 2012-05-24 02:16:41 -0700 (Thu, 24 May 2012) New Revision: 38752 Modified: trunk/modules/library/main/src/main/java/org/geotools/data/DataUtilities.java Log: Fixed up javadocs to answer the question posed by GEOT-1099 Check FeatureTypeImpl.equals and DataUtilities.compare implementations for duplicate functionality Signed-off-by: Jody Garnett <jod...@gm...> Modified: trunk/modules/library/main/src/main/java/org/geotools/data/DataUtilities.java =================================================================== --- trunk/modules/library/main/src/main/java/org/geotools/data/DataUtilities.java 2012-05-24 09:16:19 UTC (rev 38751) +++ trunk/modules/library/main/src/main/java/org/geotools/data/DataUtilities.java 2012-05-24 09:16:41 UTC (rev 38752) @@ -413,10 +413,9 @@ } /** - * Compare operation for FeatureType. - * + * Compare attribute coverage between two feature types (allowing the identification of subTypes). * <p> - * Results in: + * The comparison results in a number with the following meaning: * </p> * * <ul> @@ -429,20 +428,20 @@ * </ul> * * <p> - * Comparison is based on AttributeTypes, an IOException is thrown if the AttributeTypes are not - * compatiable. + * Comparison is based on {@link AttributeDescriptor} - the {@link #isMatch(AttributeDescriptor, AttributeDescriptor)} + * method is used to quickly confirm that the local name and java binding are compatible. * </p> * * <p> * Namespace is not considered in this opperations. You may still need to reType to get the * correct namesapce, or reorder. * </p> + * <p> + * Please note this method will not result in a stable sort if used in a {@link Comparator} + * as -1 is used to indicate incompatiblity (rather than simply "before"). * - * @param typeA - * FeatureType beind compared - * @param typeB - * FeatureType being compared against - * + * @param typeA FeatureType beind compared + * @param typeB FeatureType being compared against */ public static int compare(SimpleFeatureType typeA, SimpleFeatureType typeB) { if (typeA == typeB) { @@ -464,12 +463,8 @@ return -1; } - // may still be the same featureType - // (Perhaps they differ on namespace?) + // may still be the same featureType (Perhaps they differ on namespace?) AttributeDescriptor a; - - // may still be the same featureType - // (Perhaps they differ on namespace?) int match = 0; for (int i = 0; i < countA; i++) { @@ -488,17 +483,6 @@ if ((countA == countB) && (match == countA)) { // all attributes in typeA agreed with typeB // (same order and type) - // if (typeA.getNamespace() == null) { - // if(typeB.getNamespace() == null) { - // return 0; - // } else { - // return 1; - // } - // } else if(typeA.getNamespace().equals(typeB.getNamespace())) { - // return 0; - // } else { - // return 1; - // } return 0; } |
From: <svn...@os...> - 2012-05-24 09:16:33
|
Author: jive Date: 2012-05-24 02:16:19 -0700 (Thu, 24 May 2012) New Revision: 38751 Modified: trunk/modules/extension/xsd/xsd-wfs/src/main/java/org/geotools/wfs/CompositeFeatureCollection.java trunk/modules/library/main/src/main/java/org/geotools/data/DataUtilities.java trunk/modules/library/main/src/main/java/org/geotools/data/store/FilteringFeatureCollection.java trunk/modules/library/main/src/main/java/org/geotools/data/store/MaxFeaturesFeatureCollection.java trunk/modules/library/main/src/main/java/org/geotools/feature/collection/FilteringSimpleFeatureCollection.java trunk/modules/library/main/src/main/java/org/geotools/feature/collection/MaxSimpleFeatureCollection.java trunk/modules/library/main/src/test/java/org/geotools/data/DataUtilitiesTest.java Log: Fix for GEOT-2350 DataUtilities.bounds(fc) returns bounds of fc[0] only Coped the implementation out of DefaultFeatureCollection thanks IanS Signed-off-by: Jody Garnett <jod...@gm...> Modified: trunk/modules/extension/xsd/xsd-wfs/src/main/java/org/geotools/wfs/CompositeFeatureCollection.java =================================================================== --- trunk/modules/extension/xsd/xsd-wfs/src/main/java/org/geotools/wfs/CompositeFeatureCollection.java 2012-05-24 09:15:46 UTC (rev 38750) +++ trunk/modules/extension/xsd/xsd-wfs/src/main/java/org/geotools/wfs/CompositeFeatureCollection.java 2012-05-24 09:16:19 UTC (rev 38751) @@ -63,7 +63,7 @@ } public ReferencedEnvelope getBounds() { - return ReferencedEnvelope.reference(DataUtilities.bounds(this)); + return DataUtilities.bounds(this); } public int getCount() throws IOException { Modified: trunk/modules/library/main/src/main/java/org/geotools/data/DataUtilities.java =================================================================== --- trunk/modules/library/main/src/main/java/org/geotools/data/DataUtilities.java 2012-05-24 09:15:46 UTC (rev 38750) +++ trunk/modules/library/main/src/main/java/org/geotools/data/DataUtilities.java 2012-05-24 09:16:19 UTC (rev 38751) @@ -108,6 +108,7 @@ import org.opengis.filter.expression.Expression; import org.opengis.filter.expression.PropertyName; import org.opengis.filter.sort.SortBy; +import org.opengis.geometry.BoundingBox; import org.opengis.referencing.ReferenceIdentifier; import org.opengis.referencing.crs.CoordinateReferenceSystem; @@ -2319,22 +2320,30 @@ * @param collection * @return */ - public static Envelope bounds( + public static ReferencedEnvelope bounds( FeatureCollection<? extends FeatureType, ? extends Feature> collection) { FeatureIterator<? extends Feature> i = collection.features(); try { - ReferencedEnvelope bounds = new ReferencedEnvelope(collection.getSchema() - .getCoordinateReferenceSystem()); - if (!i.hasNext()) { - bounds.setToNull(); - return bounds; + // Implementation taken from DefaultFeatureCollection implementation - thanks IanS + CoordinateReferenceSystem crs = collection.getSchema().getCoordinateReferenceSystem(); + ReferencedEnvelope bounds = new ReferencedEnvelope(crs); + + while (i.hasNext()) { + BoundingBox geomBounds = ((SimpleFeature) i.next()).getBounds(); + // IanS - as of 1.3, JTS expandToInclude ignores "null" Envelope + // and simply adds the new bounds... + // This check ensures this behavior does not occur. + if ( ! geomBounds.isEmpty() ) { + bounds.include(geomBounds); + } } - - bounds.init(((SimpleFeature) i.next()).getBounds()); return bounds; - } finally { - i.close(); } + finally { + if( i != null ){ + i.close(); + } + } } /** Modified: trunk/modules/library/main/src/main/java/org/geotools/data/store/FilteringFeatureCollection.java =================================================================== --- trunk/modules/library/main/src/main/java/org/geotools/data/store/FilteringFeatureCollection.java 2012-05-24 09:15:46 UTC (rev 38750) +++ trunk/modules/library/main/src/main/java/org/geotools/data/store/FilteringFeatureCollection.java 2012-05-24 09:16:19 UTC (rev 38751) @@ -163,7 +163,7 @@ public ReferencedEnvelope getBounds() { //calculate manually - return ReferencedEnvelope.reference( DataUtilities.bounds( this ) ); + return DataUtilities.bounds( this ); } } Modified: trunk/modules/library/main/src/main/java/org/geotools/data/store/MaxFeaturesFeatureCollection.java =================================================================== --- trunk/modules/library/main/src/main/java/org/geotools/data/store/MaxFeaturesFeatureCollection.java 2012-05-24 09:15:46 UTC (rev 38750) +++ trunk/modules/library/main/src/main/java/org/geotools/data/store/MaxFeaturesFeatureCollection.java 2012-05-24 09:16:19 UTC (rev 38751) @@ -144,6 +144,6 @@ public ReferencedEnvelope getBounds() { //calculate manually - return ReferencedEnvelope.reference( DataUtilities.bounds( this ) ); + return DataUtilities.bounds( this ); } } Modified: trunk/modules/library/main/src/main/java/org/geotools/feature/collection/FilteringSimpleFeatureCollection.java =================================================================== --- trunk/modules/library/main/src/main/java/org/geotools/feature/collection/FilteringSimpleFeatureCollection.java 2012-05-24 09:15:46 UTC (rev 38750) +++ trunk/modules/library/main/src/main/java/org/geotools/feature/collection/FilteringSimpleFeatureCollection.java 2012-05-24 09:16:19 UTC (rev 38751) @@ -168,7 +168,7 @@ public ReferencedEnvelope getBounds() { //calculate manually - return ReferencedEnvelope.reference( DataUtilities.bounds( this ) ); + return DataUtilities.bounds( this ); } } Modified: trunk/modules/library/main/src/main/java/org/geotools/feature/collection/MaxSimpleFeatureCollection.java =================================================================== --- trunk/modules/library/main/src/main/java/org/geotools/feature/collection/MaxSimpleFeatureCollection.java 2012-05-24 09:15:46 UTC (rev 38750) +++ trunk/modules/library/main/src/main/java/org/geotools/feature/collection/MaxSimpleFeatureCollection.java 2012-05-24 09:16:19 UTC (rev 38751) @@ -161,6 +161,6 @@ public ReferencedEnvelope getBounds() { //calculate manually - return ReferencedEnvelope.reference( DataUtilities.bounds( this ) ); + return DataUtilities.bounds( this ); } } Modified: trunk/modules/library/main/src/test/java/org/geotools/data/DataUtilitiesTest.java =================================================================== --- trunk/modules/library/main/src/test/java/org/geotools/data/DataUtilitiesTest.java 2012-05-24 09:15:46 UTC (rev 38750) +++ trunk/modules/library/main/src/test/java/org/geotools/data/DataUtilitiesTest.java 2012-05-24 09:16:19 UTC (rev 38751) @@ -43,6 +43,7 @@ import org.geotools.feature.type.AttributeDescriptorImpl; import org.geotools.feature.type.AttributeTypeImpl; import org.geotools.filter.IllegalFilterException; +import org.geotools.geometry.jts.ReferencedEnvelope; import org.geotools.referencing.CRS; import org.geotools.referencing.crs.DefaultGeographicCRS; import org.geotools.test.TestData; @@ -65,6 +66,7 @@ import org.opengis.filter.expression.PropertyName; import org.opengis.referencing.crs.CoordinateReferenceSystem; +import com.vividsolutions.jts.geom.Envelope; import com.vividsolutions.jts.geom.Geometry; import org.geotools.data.memory.MemoryDataStore; @@ -486,6 +488,15 @@ assertEquals(roadFeatures.length, collection.size()); } + public void testBounds() { + SimpleFeatureCollection collection = DataUtilities + .collection(roadFeatures); + + ReferencedEnvelope expected = collection.getBounds(); + ReferencedEnvelope actual = DataUtilities.bounds( collection ); + assertEquals( expected, actual ); + } + public void testCollectionList() { SimpleFeatureCollection collection = DataUtilities .collection(Arrays.asList(roadFeatures)); |
From: <svn...@os...> - 2012-05-24 09:15:54
|
Author: jive Date: 2012-05-24 02:15:46 -0700 (Thu, 24 May 2012) New Revision: 38750 Modified: trunk/docs/developer/procedures/release.rst Log: A few release procedure fixes with respect to testing. Signed-off-by: Jody Garnett <jod...@gm...> Modified: trunk/docs/developer/procedures/release.rst =================================================================== --- trunk/docs/developer/procedures/release.rst 2012-05-24 09:15:35 UTC (rev 38749) +++ trunk/docs/developer/procedures/release.rst 2012-05-24 09:15:46 UTC (rev 38750) @@ -565,9 +565,18 @@ If you like you can ask on the developer list for a volunteer to perform these steps. -1. Unzip the geotools-2.6-M4-bin.zip archive to a clean directory. +1. Unzip the geotools-8.0-RC1-project.zip archive to a clean directory. I just unzip + in our target directory: + + cd target + unzip geotools-8.0-RC1-project.zip + cd geotools-8.0-RC1 + -2. Move or rename your ``.m2/repository`` directory. +2. Rather then move you maven repository we will change our settings:: + + <settings> + <localRepository>~\releaseRepository\</localRepository> * We do this in case a required module was accidentally excluded from the list of modules to be included in the release. You would see no error during the release process but the @@ -577,6 +586,9 @@ mvn install +4. Remember clean up your releaseReository and change settings.xml back + + Update JIRA and create a changelog ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
From: <svn...@os...> - 2012-05-24 09:15:48
|
Author: jive Date: 2012-05-24 02:15:35 -0700 (Thu, 24 May 2012) New Revision: 38749 Modified: trunk/modules/library/main/src/main/java/org/geotools/data/DataUtilities.java Log: Review of DataUtilities methods prior to 8.0 going out the door. Fixed up a few javadocs to match the actual implementations. Several methods had their exception throwing code commented out and were now returning null. Signed-off-by: Jody Garnett <jod...@gm...> Modified: trunk/modules/library/main/src/main/java/org/geotools/data/DataUtilities.java =================================================================== --- trunk/modules/library/main/src/main/java/org/geotools/data/DataUtilities.java 2012-05-24 09:15:12 UTC (rev 38748) +++ trunk/modules/library/main/src/main/java/org/geotools/data/DataUtilities.java 2012-05-24 09:15:35 UTC (rev 38749) @@ -139,12 +139,13 @@ * data/DataUtilities.java $ */ public class DataUtilities { - + /** Typemap used by {@link #createType(String, String)} methods */ static Map<String, Class> typeMap = new HashMap<String, Class>(); - + + /** Reverse type map used by {@link #encodeType(FeatureType)} */ static Map<Class, String> typeEncode = new HashMap<Class, String>(); - static FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2(null); + static FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2(); static { typeEncode.put(String.class, "String"); @@ -202,7 +203,7 @@ typeEncode.put(Date.class, "Date"); typeMap.put("Date", Date.class); } - + /** * Retrieve the attributeNames defined by the featureType * @@ -622,6 +623,15 @@ /** * Performs a deep copy of the provided object. + * <p> + * A number of tricks are used to make this as fast as possible: + * <ul> + * <li>Simple or Immutable types are copied as is (String, Integer, Float, URL, etc..)</li> + * <li>JTS Geometry objects are cloned</li> + * <li>Arrays and the Collection classes are duplicated element by element</li> + * </ul> + * This function is used recusively for (in order to handle complext features) no attempt + * is made to detect cycles at this time so your milage may vary. * * @param src * Source object @@ -747,9 +757,6 @@ * Type of feature we wish to create * * @return A new Feature of type featureType - * - * @throws IllegalAttributeException - * if we could not create featureType instance with acceptable default values */ public static SimpleFeature template(SimpleFeatureType featureType) throws IllegalAttributeException { @@ -757,20 +764,16 @@ } /** - * DOCUMENT ME! + * Use the provided featureType to create an empty feature. + * <p> + * The {@link #defaultValues(SimpleFeatureType)} method is used to generate + * the intial values (making use of {@link AttributeDescriptor#getDefaultValue()} as required. * * @param featureType - * DOCUMENT ME! * @param featureID - * DOCUMENT ME! - * - * @return DOCUMENT ME! - * - * @throws IllegalAttributeException - * DOCUMENT ME! + * @return Craeted feature */ - public static SimpleFeature template(SimpleFeatureType featureType, String featureID) - throws IllegalAttributeException { + public static SimpleFeature template(SimpleFeatureType featureType, String featureID) { return SimpleFeatureBuilder.build(featureType, defaultValues(featureType), featureID); } @@ -779,11 +782,8 @@ * * @param featureType * @return Array of values, that are good starting point for data entry - * - * @throws IllegalAttributeException */ - public static Object[] defaultValues(SimpleFeatureType featureType) - throws IllegalAttributeException { + public static Object[] defaultValues(SimpleFeatureType featureType) { return defaultValues(featureType, null); } @@ -792,16 +792,12 @@ * provided. * * @param featureType - * @param atts - * provided attributes - * + * @param providedValues * @return newly created feature - * - * @throws IllegalAttributeException + * @throws ArrayIndexOutOfBoundsException If the number of provided values does not match the featureType */ - public static SimpleFeature template(SimpleFeatureType featureType, Object[] atts) - throws IllegalAttributeException { - return SimpleFeatureBuilder.build(featureType, defaultValues(featureType, atts), null); + public static SimpleFeature template(SimpleFeatureType featureType, Object[] providedValues) { + return SimpleFeatureBuilder.build(featureType, defaultValues(featureType, providedValues), null); } /** @@ -810,16 +806,15 @@ * * @param featureType * @param featureID - * @param atts - * provided attributes + * @param providedValues provided attributes * * @return newly created feature * - * @throws IllegalAttributeException + * @throws ArrayIndexOutOfBoundsException If the number of provided values does not match the featureType */ public static SimpleFeature template(SimpleFeatureType featureType, String featureID, - Object[] atts) throws IllegalAttributeException { - return SimpleFeatureBuilder.build(featureType, defaultValues(featureType, atts), featureID); + Object[] providedValues) { + return SimpleFeatureBuilder.build(featureType, defaultValues(featureType, providedValues), featureID); } /** @@ -829,12 +824,9 @@ * @param values * * @return set of default values - * - * @throws IllegalAttributeException - * @throws ArrayIndexOutOfBoundsException + * @throws ArrayIndexOutOfBoundsException If the number of provided values does not match the featureType */ - public static Object[] defaultValues(SimpleFeatureType featureType, Object[] values) - throws IllegalAttributeException { + public static Object[] defaultValues(SimpleFeatureType featureType, Object[] values) { if (values == null) { values = new Object[featureType.getAttributeCount()]; } else if (values.length != featureType.getAttributeCount()) { @@ -842,7 +834,8 @@ } for (int i = 0; i < featureType.getAttributeCount(); i++) { - values[i] = defaultValue(featureType.getDescriptor(i)); + AttributeDescriptor descriptor = featureType.getDescriptor(i); + values[i] = descriptor.getDefaultValue(); } return values; @@ -850,18 +843,14 @@ /** * Provides a defautlValue for attributeType. - * * <p> * Will return null if attributeType isNillable(), or attempt to use Reflection, or * attributeType.parse( null ) * </p> * * @param attributeType - * * @return null for nillable attributeType, attempt at reflection - * - * @throws IllegalAttributeException - * If value cannot be constructed for attribtueType + * @deprecated Please {@link AttributeDescriptor#getDefaultValue()} */ public static Object defaultValue(AttributeDescriptor attributeType) throws IllegalAttributeException { @@ -869,7 +858,6 @@ if (value == null && !attributeType.isNillable()) { return null; // sometimes there is no valid default value :-( - // throw new IllegalAttributeException("Got null default value for non-null type."); } return value; } @@ -1057,15 +1045,13 @@ /** * Wraps up the provided feature collection in as a SimpleFeatureSource. * <p> - * This is usually done for use by the renderer; allowing it to query the feature collection as - * required. + * This is usually done for use by the renderer; allowing it to query the feature collection as required. * - * @param collection - * Feature collection providing content + * @param collection Feature collection providing content * @return FeatureSource used to wrap the content * - * @throws NullPointerException - * @throws RuntimeException + * @throws NullPointerException if any of the features are null + * @throws IllegalArgumentException If the provided collection is inconsistent (perhaps containing mixed feature types) */ public static SimpleFeatureSource source( final FeatureCollection<SimpleFeatureType, SimpleFeature> collection) { @@ -1098,11 +1084,12 @@ // } CollectionDataStore store = new CollectionDataStore(collection); + String typeName = store.getTypeNames()[0]; try { - return store.getFeatureSource(store.getTypeNames()[0]); + return store.getFeatureSource(typeName); } catch (IOException e) { - throw new RuntimeException("Something is wrong with the geotools code, " - + "this exception should not happen", e); + throw new IllegalArgumentException("CollectionDataStore inconsistent, " + + " ensure type name "+typeName+" is the same for all features", e); } } @@ -1125,20 +1112,26 @@ throws IOException, SchemaException { return new DefaultView(store.getFeatureSource(query.getTypeName()), query); } - + /** + * Returns collection from the provided feature array + * + * @param featureArray + * @return array contents as a SimpleFeatureCollection + * @deprecated Please use {@link #collection(SimpleFeature[])} and check {@link SimpleFeatureCollection#size()} to ensure contents are not empty + */ public static SimpleFeatureCollection results(SimpleFeature[] featureArray) { return results(collection(featureArray)); } /** * Returns collection if non empty. + * <p> + * Previous implementation would throw an IOException if the collection was empty; method + * is now duplicated as it does not servce a function. * * @param collection - * * @return provided collection - * - * @throws IOException - * Raised if collection was empty + * @deprecated Please check collection.size() directly to ensure your collection contains content */ public static SimpleFeatureCollection results(final SimpleFeatureCollection collection) { if (collection.size() == 0) { @@ -1222,7 +1215,9 @@ FeatureCollection<SimpleFeatureType, SimpleFeature> featureCollection) { return new DefaultFeatureCollection(featureCollection); } - + // + // Conversion (or casting) from general feature model to simple feature model + // /** * A safe cast to SimpleFeatureCollection; that will introduce a wrapper if it has to. * <p> @@ -1326,7 +1321,7 @@ if (featureType == null) { return null; } - // go through the attributes and strip out compicated contents + // go through the attributes and strip out complicated contents // List<PropertyDescriptor> attributes; Collection<PropertyDescriptor> descriptors = featureType.getDescriptors(); @@ -1414,7 +1409,9 @@ throw new IllegalArgumentException( "The provided feature store contains complex features, cannot be bridged to a simple one"); } - + // + // FeatureCollection Utility Methods + // /** * Copies the provided fetaures into a List. * @@ -1455,7 +1452,9 @@ } return fids; } - + // + // Conversion to FeatureCollection + // /** * Copies the provided features into a FeatureCollection. * <p> @@ -1555,7 +1554,9 @@ } return collection; } - + // + // Attribute Value Utility Methods + // /** * Used to compare if two values are equal. * <p> @@ -1566,7 +1567,7 @@ * * <ul> * <li>Object.equals( Object )</li> - * <li>Geometry.equals( Geometry )</li> + * <li>Geometry.equals( Geometry ) - similar to {@link Geometry#equalsExact(Geometry)}</li> * </ul> * * @param att @@ -1591,7 +1592,10 @@ return true; } - + + // + // TypeConversion methods used by FeatureReaders + // /** * Create a derived FeatureType * @@ -1723,7 +1727,9 @@ } return tb.buildFeatureType(); } - + // + // Decoding (ie Parsing) support for PropertyAttributeReader and tutorials + // /** * Utility method for FeatureType construction. * <p> @@ -1822,8 +1828,10 @@ return builder.buildFeatureType(); } + + /** - * Uses Converers to parse the provided text into the correct values to create a feature. + * Uses {@link Converters} to parse the provided text into the correct values to create a feature. * * @param type * FeatureType @@ -1833,7 +1841,6 @@ * Text representation of values * * @return newly created feature - * * @throws IllegalAttributeException */ public static SimpleFeature parse(SimpleFeatureType type, String fid, String[] text) @@ -1847,8 +1854,26 @@ return SimpleFeatureBuilder.build(type, attributes, fid); } - + // + // Encoding support for PropertyFeatureWriter + // /** + * Encode the provided featureType as a String suitable for use with {@link #createType}. + * <p> + * The format of this string acts as the "header" information for the PropertyDataStore + * implementations. + * + * Example:<pre><code>String header = "_="+DataUtilities.encodeType(schema);</code></pre> + * <p> + * For more information please review the PropertyDataStore tutorials. + * + * @param featureType + * @return String representation of featureType suitable for use with {@link #createType} + */ + public static String encodeType( FeatureType featureType ){ + return spec(featureType); + } + /** * A "quick" String representation of a FeatureType. * <p> * This string representation may be used with createType( name, spec ). @@ -1890,16 +1915,21 @@ return buf.toString(); } - - static Class type(String typeName) throws ClassNotFoundException { + /** + * Internal method to access java binding using readable typename. + * @see #createType(String, String) + */ + static Class<?> type(String typeName) throws ClassNotFoundException { if (typeMap.containsKey(typeName)) { return typeMap.get(typeName); } - return Class.forName(typeName); } - - static String typeMap(Class type) { + /** + * Internal method to access the readable typename for the provided class. + * @see #createType(String, String) + */ + static String typeMap(Class<?> type) { if (typeEncode.containsKey(type)) { return typeEncode.get(type); } @@ -1912,7 +1942,7 @@ */ return type.getName(); } - + /** * Factory method to produce Comparator based on provided Query SortBy information. * <p> |
From: <svn...@os...> - 2012-05-24 09:15:24
|
Author: jive Date: 2012-05-24 02:15:12 -0700 (Thu, 24 May 2012) New Revision: 38748 Modified: trunk/modules/library/main/src/test/java/org/geotools/data/DataUtilitiesTest.java Log: Confirm fix for GEOT-330 with respect to handling of windows network shares Signed-off-by: Jody Garnett <jod...@gm...> Modified: trunk/modules/library/main/src/test/java/org/geotools/data/DataUtilitiesTest.java =================================================================== --- trunk/modules/library/main/src/test/java/org/geotools/data/DataUtilitiesTest.java 2012-05-24 02:55:23 UTC (rev 38747) +++ trunk/modules/library/main/src/test/java/org/geotools/data/DataUtilitiesTest.java 2012-05-24 09:15:12 UTC (rev 38748) @@ -184,8 +184,13 @@ handleFile("C:\\one\\two"); handleFile("C:\\one\\two\\and three"); handleFile("D:\\"); - if (TestData.isExtensiveTest()) + if (TestData.isExtensiveTest()){ handleFile("\\\\host\\share\\file"); + // from GEOT-3300 DataUtilities.urlToFile doesn't handle network paths correctly + URL url = new URL("file", "////oehhwsfs09", "/some/path/on/the/server/filename.nds"); + File windowsShareFile = DataUtilities.urlToFile( url ); + assertNotNull(windowsShareFile); + } } else { handleFile("/one"); handleFile("one"); @@ -202,6 +207,11 @@ File file = File.createTempFile("hello", "world"); handleFile(file.getAbsolutePath()); handleFile(file.getPath()); + + // from GEOT-3300 DataUtilities.urlToFile doesn't handle network paths correctly + URL url = new URL("file", "////oehhwsfs09", "/some/path/on/the/server/filename.nds"); + File windowsShareFile = DataUtilities.urlToFile( url ); + assertNotNull(windowsShareFile); } private String replaceSlashes(String string) { |
From: <svn...@os...> - 2012-05-24 02:55:31
|
Author: bencaradocdavies Date: 2012-05-23 19:55:23 -0700 (Wed, 23 May 2012) New Revision: 38747 Modified: branches/2.7.x/modules/library/data/src/main/java/org/geotools/data/store/ContentFeatureSource.java Log: GEOS-5085: WFS 2.0 paging returns wrong features for startindex=0 Modified: branches/2.7.x/modules/library/data/src/main/java/org/geotools/data/store/ContentFeatureSource.java =================================================================== --- branches/2.7.x/modules/library/data/src/main/java/org/geotools/data/store/ContentFeatureSource.java 2012-05-24 02:39:06 UTC (rev 38746) +++ branches/2.7.x/modules/library/data/src/main/java/org/geotools/data/store/ContentFeatureSource.java 2012-05-24 02:55:23 UTC (rev 38747) @@ -470,8 +470,8 @@ query = resolvePropertyNames(query); // see if we need to enable native sorting in order to support stable paging - final int offset = query.getStartIndex() != null ? query.getStartIndex() : 0; - if(offset > 0 & query.getSortBy() == null) { + if (query.getStartIndex() != null + && (query.getSortBy() == null || query.getSortBy().length == 0)) { if(!getQueryCapabilities().supportsSorting(query.getSortBy())) throw new IOException("Feature source does not support this sorting " + "so there is no way a stable paging (offset/limit) can be performed"); @@ -508,6 +508,7 @@ } // offset + int offset = query.getStartIndex() != null ? query.getStartIndex() : 0; if( !canOffset() && offset > 0 ) { // skip the first n records for(int i = 0; i < offset && reader.hasNext(); i++) { |