/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2012, 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.data.oracle; import java.io.IOException; import java.util.ArrayList; import java.util.List; import javax.xml.transform.TransformerException; import org.geotools.data.Query; import org.geotools.data.simple.SimpleFeatureCollection; import org.geotools.data.simple.SimpleFeatureIterator; import org.geotools.data.store.ContentFeatureSource; import org.geotools.factory.CommonFactoryFinder; import org.geotools.filter.FilterTransformer; import org.geotools.jdbc.JDBCDataStoreAPITestSetup; import org.geotools.jdbc.JDBCTestSupport; import org.opengis.feature.simple.SimpleFeature; import org.opengis.filter.FilterFactory2; import org.opengis.filter.PropertyIsEqualTo; import org.opengis.filter.expression.Expression; import org.opengis.filter.expression.Function; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.Point; public class OracleNearestNeighborOnlineTest extends JDBCTestSupport { GeometryFactory geomFactory = new GeometryFactory(); @Override protected JDBCDataStoreAPITestSetup createTestSetup() { return new EmptyJDBCDataStoreAPITestSetup(new OracleTestSetup() { @Override protected void initializeDatabase() throws Exception { super.initializeDatabase(); // Non-Earth (meters) int srid = 262148; deleteSpatialTable("NEIGHBORS"); run("CREATE TABLE NEIGHBORS (id INT, magicnumber INT, geometry MDSYS.SDO_GEOMETRY, PRIMARY KEY(id))"); String sql = "INSERT INTO USER_SDO_GEOM_METADATA (TABLE_NAME, COLUMN_NAME, DIMINFO, SRID) " + "VALUES ('NEIGHBORS','geometry', MDSYS.SDO_DIM_ARRAY(MDSYS.SDO_DIM_ELEMENT('X',-180,180,0.5), " + "MDSYS.SDO_DIM_ELEMENT('Y',-90,90,0.5)), " + srid + ")"; run(sql); sql = "CREATE INDEX NEIGHBORS_GEOMETRY_IDX ON NEIGHBORS(GEOMETRY) INDEXTYPE IS MDSYS.SPATIAL_INDEX " + "PARAMETERS ('SDO_INDX_DIMS=2 LAYER_GTYPE=\"POINT\"')"; run(sql); int id = 0; for (int i = 0; i < 5; i++) { for (int j = 0; j < 5; j++) { run("INSERT INTO NEIGHBORS (id, geometry, magicnumber) VALUES (" + (++id) + "," + pointSql(srid, i * 10, j * 10) + ", " + (i * j) + ")"); } } } }); } public void testNearestNeighbor() throws Exception { FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2(null); ContentFeatureSource source = dataStore.getFeatureSource(tname("NEIGHBORS")); SimpleFeatureIterator features = execSdoNN(source, ff, -10, -10, 1, -1, null); try { assertTrue(features.hasNext()); SimpleFeature f = features.next(); Point point = (Point) f.getDefaultGeometry(); assertEquals(0.0, point.getCoordinate().x); assertEquals(0.0, point.getCoordinate().y); assertFalse(features.hasNext()); } finally { features.close(); } features = execSdoNN(source, ff, 100, 100, 1, -1, null); try { assertTrue(features.hasNext()); SimpleFeature f = features.next(); Point point = (Point) f.getDefaultGeometry(); assertEquals(40.0, point.getCoordinate().x); assertEquals(40.0, point.getCoordinate().y); assertFalse(features.hasNext()); } finally { features.close(); } features = execSdoNN(source, ff, -10, -10, 3, -1, null); try { checkSizeAndMagicNumber(features, 3, -1); } finally { features.close(); } // test using sdo_batch_size hint features = execSdoNN(source, ff, -10, -10, 3, 10, "magicnumber >= 10"); try { checkSizeAndMagicNumber(features, 3, 10); } finally { features.close(); } // test using CQL and no batch_size features = execSdoNN(source, ff, -10, -10, 3, -1, "magicnumber >= 15"); try { checkSizeAndMagicNumber(features, 1, 10); } finally { features.close(); } // test with limit greater than rows features = execSdoNN(source, ff, -10, -10, 50, -1, null); try { checkSizeAndMagicNumber(features, 25, -1); } finally { features.close(); } } private void checkSizeAndMagicNumber(SimpleFeatureIterator features, int size, int magicNumberMinValue) { int counter = 0; while (features.hasNext()) { SimpleFeature sf = features.next(); if (magicNumberMinValue > -1) { int magicNumber = ((Number) sf.getAttribute("MAGICNUMBER")).intValue(); assertTrue(magicNumber >= magicNumberMinValue); } counter++; } assertEquals(size, counter); } private SimpleFeatureIterator execSdoNN(ContentFeatureSource source, FilterFactory2 ff, double x, double y, int limit, int batch, String cql) throws IOException { List<Expression> params = new ArrayList<Expression>(); params.add(ff.literal(point(x, y))); params.add(ff.literal(limit)); if (cql != null) { params.add(ff.literal(cql)); if (batch > 0) { params.add(ff.literal(batch)); } } Function sdo_nn = ff.function("sdo_nn", params.toArray(new Expression[params.size()])); PropertyIsEqualTo equalsFilter = ff.equal(sdo_nn, ff.literal(true), false); Query query = new Query(tname("NEIGHBORS"), equalsFilter); SimpleFeatureCollection features = source.getFeatures(query); return features.features(); } private Point point(double x, double y) { return geomFactory.createPoint(new Coordinate(x, y)); } }