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()); + } +} |