Package org.geotools.arcsde.data

Source Code of org.geotools.arcsde.data.SpatialFilterTest

/*
*    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.arcsde.data;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.NoSuchElementException;

import org.geotools.data.DataStore;
import org.geotools.data.FeatureReader;
import org.geotools.data.FilteringFeatureReader;
import org.geotools.data.Query;
import org.geotools.data.Transaction;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.filter.text.ecql.ECQL;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.opengis.feature.Feature;
import org.opengis.feature.IllegalAttributeException;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.FeatureType;
import org.opengis.feature.type.PropertyDescriptor;
import org.opengis.filter.Filter;
import org.opengis.filter.FilterFactory2;
import org.opengis.filter.expression.PropertyName;
import org.opengis.filter.spatial.BBOX;
import org.opengis.filter.spatial.Within;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.LinearRing;
import com.vividsolutions.jts.geom.Polygon;
import com.vividsolutions.jts.io.ParseException;
import com.vividsolutions.jts.io.WKTReader;

/**
* @author cdillard
* @author Gabriel Roldan
*
*
* @source $URL$
*         http://svn.geotools.org/geotools/trunk/gt/modules/plugin/arcsde/datastore/src/test/java
*         /org/geotools/arcsde/data/FilterTest.java.fixme $
* @version $Id$
*/
public class SpatialFilterTest {
    private static final Comparator<SimpleFeature> FEATURE_COMPARATOR = new Comparator<SimpleFeature>() {
        public int compare(SimpleFeature f1, SimpleFeature f2) {
            return f1.getID().compareTo(f2.getID());
        }
    };

    private static final GeometryFactory gf = new GeometryFactory();

    private static TestData testData;

    private DataStore dataStore;

    private FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2(null);

    @BeforeClass
    public static void oneTimeSetUp() throws Exception {
        testData = new TestData();
        testData.setUp();

        final boolean insertTestData = true;
        testData.createTempTable(insertTestData);
    }

    @AfterClass
    public static void oneTimeTearDown() {
        boolean cleanTestTable = false;
        boolean cleanPool = true;
        testData.tearDown(cleanTestTable, cleanPool);
    }

    @Before
    public void setUp() throws Exception {
        // facilitates running a single test at a time (eclipse lets you do this
        // and it's very useful)
        if (testData == null) {
            oneTimeSetUp();
        }
        this.dataStore = testData.getDataStore();
    }

    @After
    public void tearDown() throws Exception {

    }

    private static void collectResults(FeatureReader<SimpleFeatureType, SimpleFeature> fr,
            Collection<SimpleFeature> c) throws NoSuchElementException, IOException,
            IllegalAttributeException {
        while (fr.hasNext()) {
            c.add(fr.next());
        }
    }

    /**
     * Are the two collections similar?
     *
     * @param c1 Collection first
     * @param c2 Collection second
     * @return true if they have the same content
     */
    private void assertFeatureListsSimilar(Collection<SimpleFeature> c1,
            Collection<SimpleFeature> c2) {
        assertEquals("Actual feature collection was not the expected size", c1.size(), c2.size());

        ArrayList<SimpleFeature> al1 = new ArrayList<SimpleFeature>(c1);
        ArrayList<SimpleFeature> al2 = new ArrayList<SimpleFeature>(c2);
        Collections.sort(al1, FEATURE_COMPARATOR);
        Collections.sort(al2, FEATURE_COMPARATOR);

        int n = c1.size();

        for (int i = 0; i < n; i++) {
            Feature f1 = al1.get(i);
            Feature f2 = al2.get(i);
            if (i == 0) {
                assertEquals("Feature Type", f1.getType(), f2.getType());
            }
            assertEquals("Feature[" + i + "] identifiers Equal", f1.getIdentifier().getID(), f2
                    .getIdentifier().getID());
            if (!f1.equals(f2)) {
                // go through properties and figure out differneces...
                for (PropertyDescriptor property : f1.getType().getDescriptors()) {
                    String name = property.getName().getLocalPart();
                    Object value1 = f1.getProperty(name).getValue();
                    Object value2 = f2.getProperty(name).getValue();
                    if (value1 instanceof Calendar) {
                        continue;
                    }
                    if (value1 instanceof Date) {
                        continue;
                    }

                    if (value1 instanceof Geometry) {
                        // jts geometry is not my friend
                        assertTrue("Feature[" + i + "]." + name + " geometry",
                                ((Geometry) value1).equalsTopo((Geometry) value2));
                    } else {
                        assertEquals("Feature[" + i + "]." + name, value1, value2);
                    }
                }
            }
        }
    }

    private static LineString buildSegment(double x1, double y1, double x2, double y2) {
        Coordinate[] coordArray = new Coordinate[] { new Coordinate(x1, y1), new Coordinate(x2, y2) };
        LineString result = gf.createLineString(coordArray);

        return result;
    }

    private static Polygon buildPolygon(double minx, double miny, double maxx, double maxy) {
        Coordinate[] coordArray = new Coordinate[] { new Coordinate(minx, miny),
                new Coordinate(minx, maxy), new Coordinate(maxx, maxy), new Coordinate(maxx, miny),
                new Coordinate(minx, miny) };
        Polygon p = gf.createPolygon(gf.createLinearRing(coordArray), new LinearRing[0]);

        return p;
    }

    /**
     * TODO: resurrect testDisjointFilter
     */
    @Test
    public void testDisjointFilter() throws Exception {
        FeatureType ft = this.dataStore.getSchema(testData.getTempTableName());

        // Build a polygon that intercepts some of the geometries, but not all of them
        Polygon p = buildPolygon(-180, 0, -160, 90);

        Filter filter = ff.not(ff.isNull(ff.property("SHAPE")));
        filter = ff.and(filter, ff.disjoint(ff.property("SHAPE"), ff.literal(p)));

        runTestWithFilter(ft, filter, false);
    }

    @Test
    public void testContainsFilter() throws Exception {
        FeatureType ft = this.dataStore.getSchema(testData.getTempTableName());

        // Build the filter with a polygon that is inside POLYGON((-10 -10, -10 10, 10 10, 10 -10,
        // -10 -10))
        Polygon p = buildPolygon(-9, -9, -8, -8);
        Filter filter = ff.contains(ff.property("SHAPE"), ff.literal(p));
        runTestWithFilter(ft, filter, false);

        // now build the opposite filter, the polygon contains the shape
        p = buildPolygon(-1, -1, 1, 1);
        filter = ff.contains(ff.literal(p), ff.property("SHAPE"));
        runTestWithFilter(ft, filter, false);
    }

    @Test
    public void testContainsSDESemanticsFilter() throws Exception {
        FeatureType ft = this.dataStore.getSchema(testData.getTempTableName());

        // Build a filter so that SDE would actually catch more geometries, it would
        // actually include
        // "MULTIPOLYGON( ((-1 -1, -1 1, 1 1, 1 -1, -1 -1)), ((-170 -80, -170 -70, -160 -70, -160 -80, -170 -80)) )"
        // in the results as well. It seems the containment semantics is applied in or to the
        // multigeometry
        // components. We do in memory post filtering to get the right semantics
        Polygon p = buildPolygon(-1, -1, 1, 1);
        Filter filter = ff.contains(ff.property("SHAPE"), ff.literal(p));
        runTestWithFilter(ft, filter, false);

        // now build the opposite filter, the polygon contains the shape
        p = buildPolygon(-1, -1, 1, 1);
        filter = ff.contains(ff.literal(p), ff.property("SHAPE"));
        runTestWithFilter(ft, filter, false);
    }

    @Test
    public void testBBoxFilter() throws Exception {
        FeatureType ft = this.dataStore.getSchema(testData.getTempTableName());

        // Build the filter
        Filter filter = ff.bbox("SHAPE", -1, -1, 1, 1, "EPSG:4326");

        runTestWithFilter(ft, filter, false);
    }

    @Test
    public void testOrBBoxFilter() throws Exception {
        FeatureType ft = this.dataStore.getSchema(testData.getTempTableName());

        System.out
                .println(this.dataStore.getFeatureSource(ft.getName().getLocalPart()).getBounds());

        // build a or of bbox so that
        // - the intersection of the bboxes is empty
        // - the union of the bboxes actually gets more data than necessary
        BBOX bbox1 = ff.bbox("SHAPE", -171, -90, -169, 90, "EPSG:4326");
        BBOX bbox2 = ff.bbox("SHAPE", 169, -90, 171, 90, "EPSG:4326");
        Filter filter = ff.or(bbox1, bbox2);

        runTestWithFilter(ft, filter, false);
    }

    @Test
    public void testIntersectsFilter() throws Exception {
        FeatureType ft = this.dataStore.getSchema(testData.getTempTableName());

        // Build the filter
        Polygon p = buildPolygon(-1, -1, 1, 1);
        Filter filter = ff.intersects(ff.property("SHAPE"), ff.literal(p));

        runTestWithFilter(ft, filter, false);
    }

    @Test
    public void testOverlapsFilter() throws Exception {
        FeatureType ft = this.dataStore.getSchema(testData.getTempTableName());

        // Build the filter
        Polygon p = buildPolygon(-10, -10, -8, -8);
        Filter filter = ff.overlaps(ff.property("SHAPE"), ff.literal(p));

        runTestWithFilter(ft, filter, false);
    }

    @Test
    public void testWithinFilter() throws Exception {
        FeatureType ft = this.dataStore.getSchema(testData.getTempTableName());

        // Build the filter
        Polygon p = buildPolygon(-9, -9, -8, -8);
        Within filter = ff.within(ff.literal(p), ff.property("SHAPE"));
        runTestWithFilter(ft, filter, false);

        // now build the opposite filter, the polygon contains the shape
        p = buildPolygon(-1, -1, 1, 1);
        filter = ff.within(ff.property("SHAPE"), ff.literal(p));
        runTestWithFilter(ft, filter, false);
    }

    @Test
    public void testCrossesFilter() throws Exception {
        FeatureType ft = this.dataStore.getSchema(testData.getTempTableName());

        // Build the filter
        LineString ls = buildSegment(-12, -12, 12, 12);
        Filter filter = ff.crosses(ff.property("SHAPE"), ff.literal(ls));

        runTestWithFilter(ft, filter, false);
    }

    /**
     * TODO: resurrect testEqualFilter
     */
    @Test
    public void testEqualFilter() throws Exception {
        FeatureType ft = this.dataStore.getSchema(testData.getTempTableName());

        // Get a geometry for equality comparison
        Query Query = new Query(testData.getTempTableName());
        Query.setPropertyNames(safePropertyNames(ft));
        Query.setMaxFeatures(1);
        FeatureReader<SimpleFeatureType, SimpleFeature> fr = this.dataStore.getFeatureReader(Query,
                Transaction.AUTO_COMMIT);
        SimpleFeature feature = fr.next();
        fr.close();

        Geometry g = (Geometry) feature.getAttribute("SHAPE");

        // Build the filter
        Filter filter = ff.equal(ff.property("SHAPE"), ff.literal(g));

        runTestWithFilter(ft, filter, false);
    }

    @Test
    public void testDwithinFilter() throws Exception {
        FeatureType ft = this.dataStore.getSchema(testData.getTempTableName());

        // Available geometries:
        // 1. POINT(0 0)
        // 2. MULTIPOINT(0 0, 170 0)
        // 3. LINESTRING(0 0, 170 80)
        // 4. MULTILINESTRING((-170 -80, 170 80), (-170 80, 170 -80))
        // 5. POLYGON((-10 -10, -10 10, 10 10, 10 -10, -10 -10))
        // 6. MULTIPOLYGON( ((-1 -1, -1 1, 1 1, 1 -1, -1 -1)), ((-170 -80, -170 -70, -160 -70, -160
        // -80, -170 -80)) )
        // 7. POINT EMPTY
        // 8. null

        final PropertyName property = ff.property("SHAPE");
        Geometry geom;
        Filter filter;

        geom = geom("POINT(170 0)");
        filter = ff.dwithin(property, ff.literal(geom), 1d, "");
        runTestWithFilter(ft, filter, false, 1);

        geom = geom("POINT(-1 -1)");
        filter = ff.dwithin(property, ff.literal(geom), 0.1, "");
        runTestWithFilter(ft, filter, false, 2);// geoms 4. and 6.
    }

    @Test
    public void testBeyondFilter() throws Exception {
        FeatureType ft = this.dataStore.getSchema(testData.getTempTableName());

        // Available geometries:
        // 1. POINT(0 0)
        // 2. MULTIPOINT(0 0, 170 0)
        // 3. LINESTRING(0 0, 170 80)
        // 4. MULTILINESTRING((-170 -80, 170 80), (-170 80, 170 -80))
        // 5. POLYGON((-10 -10, -10 10, 10 10, 10 -10, -10 -10))
        // 6. MULTIPOLYGON( ((-1 -1, -1 1, 1 1, 1 -1, -1 -1)), ((-170 -80, -170 -70, -160 -70, -160
        // -80, -170 -80)) )
        // 7. POINT EMPTY
        // 8. null

        final PropertyName property = ff.property("SHAPE");
        Geometry geom;
        Filter filter;

        geom = geom("POINT(170 0)");
        filter = ff.beyond(property, ff.literal(geom), 1d, "");
        runTestWithFilter(ft, filter, false, 5);// all non null but geom 2.

        geom = geom("POINT(-1 -1)");
        filter = ff.beyond(property, ff.literal(geom), 0.1, "");
        runTestWithFilter(ft, filter, false, 4);// all non null but geoms 4. and 6.
    }

    @Test
    public void testTouches() throws Exception {
        FeatureType ft = this.dataStore.getSchema(testData.getTempTableName());

        // Available geometries:
        // INT32_COL SHAPE
        // --------- --------
        // 1. ------ POINT(0 0)
        // 2. ------ MULTIPOINT(0 0, 170 0)
        // 3. ------ LINESTRING(0 0, 170 80)
        // 4. ------ MULTILINESTRING((-170 -80, 170 80), (-170 80, 170 -80))
        // 5. ------ POLYGON((-10 -10, -10 10, 10 10, 10 -10, -10 -10))
        // 6. ------ MULTIPOLYGON( ((-1 -1, -1 1, 1 1, 1 -1, -1 -1)),
        // ((-170 -80, -170 -70, -160 -70, -160 -80, -170 -80)) )
        // 7. ------ POINT EMPTY
        // 8. ------ null

        final PropertyName property = ff.property("SHAPE");
        Geometry geom;
        Filter filter;

        geom = findGeom("INT32_COL = 3");
        filter = ff.touches(property, ff.literal(geom));
        runTestWithFilter(ft, filter, false, 2);// features 1. and 2.

        // doesn't touch itself
        geom = findGeom("INT32_COL = 3");
        filter = ff.and(ff.equals(ff.property("INT32_COL"), ff.literal(3)),
                ff.touches(property, ff.literal(geom)));
        runTestWithFilter(ft, filter, true);// empty

        geom = findGeom("INT32_COL = 3").getBoundary().getGeometryN(0);// first point of 3.
        filter = ff.touches(property, ff.literal(geom));
        runTestWithFilter(ft, filter, false, 1);

        geom = findGeom("INT32_COL = 6");
        filter = ff.touches(property, ff.literal(geom));
        runTestWithFilter(ft, filter, true);// empty, polygon intersects

        geom = findGeom("INT32_COL = 6").getBoundary();
        filter = ff.touches(property, ff.literal(geom));
        runTestWithFilter(ft, filter, false, 1);// true, polygon boundary touches polygon

        geom = findGeom("INT32_COL = 4").getGeometryN(0);
        filter = ff.touches(property, ff.literal(geom));
        runTestWithFilter(ft, filter, false, 1);

    }

    /**
     * @param string
     * @return
     */
    private Geometry findGeom(String cql) throws Exception {

        Query query = new Query(testData.getTempTableName());
        query.setFilter(ECQL.toFilter(cql));
        FeatureReader<SimpleFeatureType, SimpleFeature> fr = this.dataStore.getFeatureReader(query,
                Transaction.AUTO_COMMIT);
        SimpleFeature feature = fr.next();
        fr.close();
        return (Geometry) feature.getDefaultGeometry();
    }

    private void runTestWithFilter(FeatureType ft, Filter filter, boolean empty) throws Exception {
        runTestWithFilter(ft, filter, empty, null);
    }

    private Geometry geom(String wkt) {
        try {
            return new WKTReader().read(wkt);
        } catch (ParseException e) {
            throw new IllegalArgumentException(e);
        }
    }

    private void runTestWithFilter(FeatureType ft, Filter filter, boolean empty, /* Nullable */
            Integer expectedCount) throws Exception {
        System.err.println("****************");
        System.err.println("**");
        System.err.println("** TESTING FILTER: " + filter);
        System.err.println("**");
        System.err.println("****************");

        // First, read using the slow, built-in mechanisms
        String[] propertyNames = safePropertyNames(ft);
        final String typeName = testData.getTempTableName();
        Query allQuery = new Query(typeName, Filter.INCLUDE, propertyNames);
        System.err.println("Performing slow read...");

        long startTime = System.currentTimeMillis();
        FeatureReader<SimpleFeatureType, SimpleFeature> fr = this.dataStore.getFeatureReader(
                allQuery, Transaction.AUTO_COMMIT);
        FilteringFeatureReader<SimpleFeatureType, SimpleFeature> ffr = new FilteringFeatureReader<SimpleFeatureType, SimpleFeature>(
                fr, filter);
        ArrayList<SimpleFeature> slowResults = new ArrayList<SimpleFeature>();
        collectResults(ffr, slowResults);
        ffr.close();

        long endTime = System.currentTimeMillis();
        System.err.println("Slow read took " + (endTime - startTime) + " milliseconds.");

        // Now read using DataStore's mechanisms.
        System.err.println("Performing fast read...");
        startTime = System.currentTimeMillis();

        Query filteringQuery = new Query(testData.getTempTableName(), filter, safePropertyNames(ft));
        fr = this.dataStore.getFeatureReader(filteringQuery, Transaction.AUTO_COMMIT);

        ArrayList<SimpleFeature> fastResults = new ArrayList<SimpleFeature>();
        collectResults(fr, fastResults);
        fr.close();
        endTime = System.currentTimeMillis();
        System.err.println("Fast read took " + (endTime - startTime) + " milliseconds.");

        assertFeatureListsSimilar(slowResults, fastResults);

        if (expectedCount != null) {
            assertEquals(expectedCount.intValue(), slowResults.size());
            assertEquals(expectedCount.intValue(), fastResults.size());
        }

        if (empty) {
            assertEquals("Result was supposed to be empty", 0, fastResults.size());
        } else {
            assertTrue("Result was supposed to be non empty", fastResults.size() > 0);
        }

    }

    private String[] safePropertyNames(FeatureType ft) {
        ArrayList<String> names = new ArrayList<String>();
        for (PropertyDescriptor descriptor : ft.getDescriptors()) {
            Class<?> binding = descriptor.getType().getBinding();
            if (Calendar.class.equals(binding)) {
                continue;
            }
            if (Date.class.equals(binding)) {
                continue;
            }
            names.add(descriptor.getName().getLocalPart());
        }
        String[] propertyNames = names.toArray(new String[names.size()]);
        return propertyNames;
    }

}
TOP

Related Classes of org.geotools.arcsde.data.SpatialFilterTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.