Skip to content

Commit

Permalink
[GEOT-4121] DWithin filter does not work from GeoServer when passing …
Browse files Browse the repository at this point in the history
…units parameter

git-svn-id: http://svn.osgeo.org/geotools/trunk@38695 e5c1c795-43da-0310-a71f-fac65c449510
  • Loading branch information
aaime committed Apr 30, 2012
1 parent 78d5f81 commit defd4a1
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 3 deletions.
Expand Up @@ -308,7 +308,8 @@ protected void doSDORelate(Filter filter, Expression e1, Expression e2, boolean
protected void doSDODistance(BinarySpatialOperator filter,
Expression e1, Expression e2, Object extraData) throws IOException {
double distance = ((DistanceBufferOperator) filter).getDistance();
String unit = ((DistanceBufferOperator) filter).getDistanceUnits();
String unit = getSDOUnitFromOGCUnit(((DistanceBufferOperator) filter).getDistanceUnits());

String within = filter instanceof DWithin ? "TRUE" : "FALSE";

out.write("SDO_WITHIN_DISTANCE(");
Expand All @@ -322,5 +323,28 @@ protected void doSDODistance(BinarySpatialOperator filter,
else
out.write(",'distance=" + distance + "') = '" + within + "' ");
}


/**
* The mapping between OGC filter units and Oracle Units.
* The full list of Oracle Units can be obtained by issuing
* "select * from MDSYS.SDO_DIST_UNITS WHERE SDO_UNIT IS NOT NULL order by SDO_UNIT;"
*/
private static final Map<String, String> UNITS_MAP = new HashMap<String, String>() {
{
put("metre", "m");
put("meters", "m");
put("kilometers", "km");
put("mi", "Mile");
put("miles", "Mile");
put("NM", "naut_mile");
put("feet", "foot");
put("ft", "foot");
put("in", "inch");
}
};

private static String getSDOUnitFromOGCUnit(String ogcUnit) {
Object sdoUnit = UNITS_MAP.get(ogcUnit);
return sdoUnit != null ? sdoUnit.toString() : ogcUnit;
}
}
Expand Up @@ -16,12 +16,24 @@
*/
package org.geotools.data.oracle;

import org.geotools.data.Query;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.feature.FeatureCollection;
import org.geotools.jdbc.JDBCDataStoreAPITestSetup;
import org.geotools.jdbc.JDBCSpatialFiltersTest;
import org.opengis.filter.FilterFactory;
import org.opengis.filter.FilterFactory2;
import org.opengis.filter.expression.Literal;
import org.opengis.filter.expression.PropertyName;
import org.opengis.filter.spatial.BBOX;
import org.opengis.filter.spatial.DWithin;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryCollection;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.Point;

/**
*
Expand All @@ -44,4 +56,45 @@ public void testLooseBboxFilter() throws Exception {
FeatureCollection features = dataStore.getFeatureSource(tname("road")).getFeatures(bbox);
checkSingleResult(features, "r2");
}

// As reported in GEOS-4384 (http://jira.codehaus.org/browse/GEOS-4384)
public void testSDODWithinOGCUnits() throws Exception {
// express the same distance in different ways and check results
validateOGCUnitUsage(10, "kilometers");
validateOGCUnitUsage(10, "km");
validateOGCUnitUsage(10, "kilometer");
// this one does not work... not sure why
// validateOGCUnitUsage(10000 * 1000, "mm");
validateOGCUnitUsage(10000, "m");
validateOGCUnitUsage(10000, "metre");
validateOGCUnitUsage(10000, "meters");
validateOGCUnitUsage(10000 / 0.0254, "in");
validateOGCUnitUsage(10000 / 0.3048, "feet");
validateOGCUnitUsage(10000 / 0.3048, "foot");
validateOGCUnitUsage(10000 / 0.3048, "ft");
validateOGCUnitUsage(10000 / 1609.344, "mi");
validateOGCUnitUsage(10000 / 1609.344, "mile");
validateOGCUnitUsage(10000 / 1609.344, "miles");
validateOGCUnitUsage(10000 / 1852, "NM");
}

private void validateOGCUnitUsage(double distance, String unit) throws Exception {
Coordinate coordinate = new Coordinate(3.031, 2.754);
GeometryFactory factory = new GeometryFactory();
Point point = factory.createPoint(coordinate);
Geometry[] geometries = {point};
GeometryCollection geometry = new GeometryCollection(geometries, factory );

FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2(null);

PropertyName geomName = ff.property(aname("geom"));
Literal lit = ff.literal(geometry);

DWithin dwithinGeomFilter = ((FilterFactory2) ff).dwithin(geomName, lit, distance, unit);
Query query = new Query(tname("road"), dwithinGeomFilter);
SimpleFeatureCollection features = dataStore.getFeatureSource(tname("road")).getFeatures(query);
assertEquals(1, features.size());
checkSingleResult(features, "r2");
}

}
Expand Up @@ -24,7 +24,9 @@
import java.sql.Time;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.geotools.data.jdbc.FilterToSQL;
import org.geotools.factory.CommonFactoryFinder;
Expand Down Expand Up @@ -90,6 +92,24 @@ class FilterToSqlHelper {

protected static final String IO_ERROR = "io problem writing filter";

/**
* Conversion factor from common units to meter
*/
private static final Map<String, Double> UNITS_MAP = new HashMap<String, Double>() {
{
put("kilometers", 1000.0);
put("kilometer", 1000.0);
put("mm", 0.001);
put("millimeter", 0.001);
put("mi", 1609.344);
put("miles", 1609.344);
put("NM", 1852d);
put("feet", 0.3048);
put("ft", 0.3048);
put("in", 0.0254);
}
};

private static final Envelope WORLD = new Envelope(-180, 180, -90, 90);

FilterToSQL delegate;
Expand Down Expand Up @@ -193,7 +213,7 @@ void visitDistanceSpatialOperator(DistanceBufferOperator filter,
out.write(",");
geometry.accept(delegate, extraData);
out.write(",");
out.write(Double.toString(filter.getDistance()));
out.write(toMeters(filter.getDistance(), filter.getDistanceUnits()));
out.write(")");
}
if ((filter instanceof DWithin && swapped)
Expand All @@ -207,6 +227,19 @@ void visitDistanceSpatialOperator(DistanceBufferOperator filter,
}
}

private String toMeters(double distance, String unit) {
// only geography uses metric units
if(isCurrentGeography()) {
Double conversion = UNITS_MAP.get(unit);
if(conversion != null) {
return String.valueOf(distance * conversion);
}
}

// in case unknown unit or not geography, use as-is
return String.valueOf(distance);
}

void visitComparisonSpatialOperator(BinarySpatialOperator filter,
PropertyName property, Literal geometry, boolean swapped, Object extraData)
throws IOException {
Expand Down
Expand Up @@ -16,10 +16,26 @@
*/
package org.geotools.data.postgis;

import org.geotools.data.Query;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureIterator;
import org.geotools.jdbc.JDBCDataStore;
import org.geotools.jdbc.JDBCGeographyTest;
import org.geotools.jdbc.JDBCGeographyTestSetup;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.filter.FilterFactory2;
import org.opengis.filter.expression.Literal;
import org.opengis.filter.expression.PropertyName;
import org.opengis.filter.spatial.DWithin;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryCollection;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.Point;

/**
*
Expand All @@ -45,4 +61,53 @@ public void testSchema() throws Exception {
SimpleFeatureType ft = dataStore.getFeatureSource(tname("geopoint")).getSchema();
assertEquals("geography", ft.getGeometryDescriptor().getUserData().get(JDBCDataStore.JDBC_NATIVE_TYPENAME));
}

// As reported in GEOS-4384 (http://jira.codehaus.org/browse/GEOS-4384)
public void testDWithinOGCUnits() throws Exception {
validateOGCUnitUsage(10000, "m");
validateOGCUnitUsage(10000, "metre");
validateOGCUnitUsage(10000, "meters");
validateOGCUnitUsage(10000 * 1000, "mm");
validateOGCUnitUsage(10, "kilometers");
validateOGCUnitUsage(10, "km");
validateOGCUnitUsage(10, "kilometer");
validateOGCUnitUsage(10000 / 0.0254, "in");
validateOGCUnitUsage(10000 / 0.3048, "feet");
validateOGCUnitUsage(10000 / 0.3048, "foot");
validateOGCUnitUsage(10000 / 0.3048, "ft");
validateOGCUnitUsage(10000 / 1609.344, "mi");
validateOGCUnitUsage(10000 / 1609.344, "mile");
validateOGCUnitUsage(10000 / 1609.344, "miles");
validateOGCUnitUsage(10000 / 1852, "NM");
}

private void validateOGCUnitUsage(double distance, String unit) throws Exception {
Coordinate coordinate = new Coordinate(-110, 30);
GeometryFactory factory = new GeometryFactory();
Point point = factory.createPoint(coordinate);
Geometry[] geometries = {point};
GeometryCollection geometry = new GeometryCollection(geometries, factory );

FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2(null);

PropertyName geomName = ff.property(aname("geo"));
Literal lit = ff.literal(geometry);

DWithin dwithinGeomFilter = ((FilterFactory2) ff).dwithin(geomName, lit, distance, unit);
Query query = new Query(tname("geopoint"), dwithinGeomFilter);
SimpleFeatureCollection features = dataStore.getFeatureSource(tname("geopoint")).getFeatures(query);
assertEquals(1, features.size());
checkSingleResult(features, "Town");
}

protected void checkSingleResult(FeatureCollection features, String name) {
assertEquals(1, features.size());
FeatureIterator fr = features.features();
assertTrue(fr.hasNext());
SimpleFeature f = (SimpleFeature) fr.next();
assertNotNull(f);
assertEquals(name, f.getAttribute(aname("name")));
assertFalse(fr.hasNext());
fr.close();
}
}

0 comments on commit defd4a1

Please sign in to comment.