/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2002-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; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import org.geotools.factory.CommonFactoryFinder; import org.geotools.util.Converters; import org.opengis.feature.simple.SimpleFeature; import org.opengis.filter.MultiValuedFilter.MatchAction; import com.vividsolutions.jts.geom.Geometry; /** * Implements a geometry filter. * *
* This filter implements a relationship - of some sort - between two geometry * expressions. Note that this comparison does not attempt to restict its * expressions to be meaningful. This means that it considers itself a valid * filter as long as it contains two geometry sub-expressions. It is * also slightly less restrictive than the OGC Filter specification because * it does not require that one sub-expression be an geometry attribute and * the other be a geometry literal. *
* ** In other words, you may use this filter to compare two geometries in the * same feature, such as: attributeA inside attributeB? You may also compare * two literal geometries, although this is fairly meaningless, since it could * be reduced (ie. it is always either true or false). This approach is very * similar to that taken in the FilterCompare class. *
* * @author Rob Hranac, TOPP * * * @source $URL$ * @version $Id$ * * @task REVISIT: make this class (and all filters) immutable, implement * cloneable and return new filters when calling addLeftGeometry and * addRightG Issues to think through: would be cleaner immutability to * have constructor called with left and right Geometries, but this does * not jive with SAX parsing, which is one of the biggest uses of * filters. But the alternative is not incredibly efficient either, as * there will be two filters that are just thrown away every time we * make a full geometry filter. These issues extend to most filters, as * just about all of them are mutable when creating them. Other issue * is that lots of code will need to be changed for immutability. * (comments by cholmes) - MUTABLE FACTORIES! Sax and immutability. */ public abstract class GeometryFilterImpl extends BinaryComparisonAbstract implements GeometryFilter { /** Class logger */ private static final Logger LOGGER = org.geotools.util.logging.Logging.getLogger("org.geotools.filter"); protected MatchAction matchAction; protected GeometryFilterImpl(org.opengis.filter.FilterFactory factory, MatchAction matchAction) { super(factory); this.matchAction = matchAction; } protected GeometryFilterImpl(org.opengis.filter.FilterFactory factory,org.opengis.filter.expression.Expression e1,org.opengis.filter.expression.Expression e2, MatchAction matchAction) { super(factory,e1,e2); this.matchAction = matchAction; } protected GeometryFilterImpl(org.opengis.filter.FilterFactory factory) { this (factory, MatchAction.ANY); } protected GeometryFilterImpl(org.opengis.filter.FilterFactory factory,org.opengis.filter.expression.Expression e1,org.opengis.filter.expression.Expression e2) { this(factory,e1,e2, MatchAction.ANY); } /** * Constructor with filter type. * * @param filterType The type of comparison. * * @throws IllegalFilterException Non-geometry type. */ protected GeometryFilterImpl(short filterType) throws IllegalFilterException { super(CommonFactoryFinder.getFilterFactory(null)); if (isGeometryFilter(filterType)) { this.filterType = filterType; } else { throw new IllegalFilterException("Attempted to create geometry " + "filter with non-geometry type."); } } /** * Adds the 'left' value to this filter. * * @param leftGeometry Expression for 'left' value. * * @throws IllegalFilterException Filter is not internally consistent. * * @deprecated use {@link #setExpression1(org.opengis.filter.expression.Expression)} */ public final void addLeftGeometry(Expression leftGeometry) throws IllegalFilterException { setExpression1(leftGeometry); } public void setExpression1(org.opengis.filter.expression.Expression expression) { if (expression instanceof Expression) { Expression leftGeometry = (Expression) expression; // Checks if this is geometry filter or not and handles appropriately if (DefaultExpression.isGeometryExpression(leftGeometry.getType()) || permissiveConstruction) { super.setExpression1(leftGeometry); } else { throw new IllegalFilterException("Attempted to add (left)" + " non-geometry expression" + " to geometry filter."); } } else { // I guess we assume it is a good expression... super.setExpression1(expression); } } /** * Adds the 'right' value to this filter. * * @param rightGeometry Expression for 'right' value. * * @throws IllegalFilterException Filter is not internally consistent. * * @deprecated use {@link #set} * */ public final void addRightGeometry(Expression rightGeometry) throws IllegalFilterException { setExpression2(rightGeometry); } public void setExpression2(org.opengis.filter.expression.Expression expression) { if (expression instanceof Expression) { Expression rightGeometry = (Expression) expression; // Checks if this is math filter or not and handles appropriately if (DefaultExpression.isGeometryExpression(rightGeometry.getType()) || permissiveConstruction) { super.setExpression2(rightGeometry); } else { throw new IllegalFilterException("Attempted to add (right)" + " non-geometry" + "expression to geometry filter."); } } else { // I guess we assume it is a good expression... super.setExpression2(expression); } } /** * Retrieves the expression on the left side of the comparison. * * @return the expression on the left. * @deprecated use {@link org.opengis.filter.spatial.BinarySpatialOperator#getExpression1()} */ public final Expression getLeftGeometry() { return (Expression)getExpression1(); } /** * Retrieves the expression on the right side of the comparison. * * @return the expression on the right. * @deprecated use {@link org.opengis.filter.spatial.BinarySpatialOperator#getExpression2()} */ public final Expression getRightGeometry() { return (Expression)getExpression2(); } /** * Subclass convenience method for returning left expression as a * JTS geometry. * * * @deprecated use {@link org.geotools.filter#getGeometries(org.opengis.filter.expression.Expression expr, Object feature)} */ protected Geometry getLeftGeometry(Object feature) { org.opengis.filter.expression.Expression leftGeometry = getExpression1(); if (leftGeometry != null) { Object obj = leftGeometry.evaluate(feature,Geometry.class); //LOGGER.finer("leftGeom = " + o.toString()); return (Geometry) obj; } else if (feature instanceof SimpleFeature) { return (Geometry) ((SimpleFeature)feature).getDefaultGeometry(); } return null; } /** * Subclass convenience method for returning right expression as a * JTS geometry. * * @deprecated use {@link org.geotools.filter#getGeometries(org.opengis.filter.expression.Expression expr, Object feature)} */ protected Geometry getRightGeometry(Object feature) { org.opengis.filter.expression.Expression rightGeometry = getExpression2(); if (rightGeometry != null) { return (Geometry) rightGeometry.evaluate(feature,Geometry.class); } else if(feature instanceof SimpleFeature){ return (Geometry) ((SimpleFeature)feature).getDefaultGeometry(); } return null; } /** * NC - support for multiple values * Convenience method for returning expression as either a geometry or a list of geometries. */ protected static Object getGeometries(org.opengis.filter.expression.Expression expr, Object feature) { Object o = expr.evaluate(feature); if (o instanceof Collection) { List