All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.geotools.data.collection.SpatialIndexFeatureSource Maven / Gradle / Ivy

Go to download

The main module contains the GeoTools public interfaces that are used by other GeoTools modules (and GeoTools applications). Where possible we make use industry standard terms as provided by OGC and ISO standards. The formal GeoTools public api consists of gt-metadata, jts and the gt-main module. The main module contains the default implementations that are available provided to other GeoTools modules using our factory system. Factories are obtained from an appropriate FactoryFinder, giving applications a chance configure the factory used using the Factory Hints facilities. FilterFactory ff = CommonFactoryFinder.getFilterFactory(); Expression expr = ff.add( expression1, expression2 ); If you find yourself using implementation specific classes chances are you doing it wrong: Expression expr = new AddImpl( expression1, expressiom2 );

There is a newer version: 24.2-oss84-1
Show newest version
/*
 *    GeoTools - The Open Source Java GIS Toolkit
 *    http://geotools.org
 *
 *    (C) 2019, 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.collection;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.geotools.data.DataStore;
import org.geotools.data.DataUtilities;
import org.geotools.data.FeatureListener;
import org.geotools.data.Query;
import org.geotools.data.QueryCapabilities;
import org.geotools.data.ResourceInfo;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.data.store.EmptyFeatureCollection;
import org.geotools.data.store.ReTypingFeatureCollection;
import org.geotools.data.store.ReprojectingFeatureCollection;
import org.geotools.feature.collection.MaxSimpleFeatureCollection;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.locationtech.jts.geom.Envelope;
import org.locationtech.jts.geom.Geometry;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.Name;
import org.opengis.filter.And;
import org.opengis.filter.Filter;
import org.opengis.filter.expression.Expression;
import org.opengis.filter.expression.Literal;
import org.opengis.filter.expression.PropertyName;
import org.opengis.filter.sort.SortBy;
import org.opengis.filter.spatial.BBOX;
import org.opengis.filter.spatial.BinarySpatialOperator;
import org.opengis.filter.spatial.Contains;
import org.opengis.filter.spatial.Crosses;
import org.opengis.filter.spatial.DWithin;
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;

/**
 * A FeatureSource using a spatial index to hold on to features and serve them up for fast display.
 *
 * 

This is a port of Andrea's CachingFeatureSource (which is slightly more compliced and rebuilds * the cache as an origional feature source changes). Our implementation here knows up front that * the features are in memory and does its best to take advantage of the fact. A caching feature * source for fast data access. * *

Please note that this FeatureSource is strictly "read-only" and thus does not support feature * events. */ public class SpatialIndexFeatureSource implements SimpleFeatureSource { SpatialIndexFeatureCollection contents; private static final Set supportedFilterTypes = new HashSet( Arrays.asList( BBOX.class, Contains.class, Crosses.class, DWithin.class, Equals.class, Intersects.class, Overlaps.class, Touches.class, Within.class)); public SpatialIndexFeatureSource(SpatialIndexFeatureCollection original) { this.contents = original; } public void addFeatureListener(FeatureListener listener) {} public void removeFeatureListener(FeatureListener listener) {} public DataStore getDataStore() { return null; // not applicable } public ReferencedEnvelope getBounds() throws IOException { return contents.getBounds(); } public ReferencedEnvelope getBounds(Query query) throws IOException { return getFeatures(query).getBounds(); } public int getCount(Query query) throws IOException { return getFeatures(query).size(); } public SimpleFeatureType getSchema() { return contents.getSchema(); } public SimpleFeatureCollection getFeatures() throws IOException { return contents; } public SimpleFeatureCollection getFeatures(Filter filter) throws IOException { Query query = new Query(getSchema().getName().getLocalPart(), filter); return getFeatures(query); } public SimpleFeatureCollection getFeatures(Query query) throws IOException { Envelope bounds = getEnvelope(query.getFilter()); return getFeatureCollection(query, bounds); } private SimpleFeatureCollection getFeatureCollection(Query query, Envelope bounds) throws IOException { query = DataUtilities.resolvePropertyNames(query, getSchema()); final int offset = query.getStartIndex() != null ? query.getStartIndex() : 0; if (offset > 0 && query.getSortBy() == null) { if (!getQueryCapabilities().supportsSorting(query.getSortBy())) { throw new IllegalStateException( "Feature source does not support this sorting " + "so there is no way a stable paging (offset/limit) can be performed"); } Query copy = new Query(query); copy.setSortBy(new SortBy[] {SortBy.NATURAL_ORDER}); query = copy; } SimpleFeatureCollection collection; // step one filter if (query.getFilter() != null && query.getFilter().equals(Filter.EXCLUDE)) { return new EmptyFeatureCollection(getSchema()); } if (query.getFilter() != null && query.getFilter().equals(Filter.INCLUDE)) { collection = contents; } if (query.getFilter() != null && query.getFilter().equals(Filter.INCLUDE)) { collection = contents; } else { collection = contents.subCollection(query.getFilter()); } // step two: reproject if (query.getCoordinateSystemReproject() != null) { collection = new ReprojectingFeatureCollection( collection, query.getCoordinateSystemReproject()); } // step two sort! (note this makes a sorted copy) if (query.getSortBy() != null && query.getSortBy().length != 0) { SimpleFeature array[] = collection.toArray(new SimpleFeature[collection.size()]); // Arrays sort is stable (not resorting equal elements) for (SortBy sortBy : query.getSortBy()) { Comparator comparator = DataUtilities.sortComparator(sortBy); Arrays.sort(array, comparator); } ArrayList list = new ArrayList(Arrays.asList(array)); collection = new ListFeatureCollection(getSchema(), list); } // step three skip to start and return max number of fetaures if (offset > 0 || !query.isMaxFeaturesUnlimited()) { long max = Long.MAX_VALUE; if (!query.isMaxFeaturesUnlimited()) { max = query.getMaxFeatures(); } collection = new MaxSimpleFeatureCollection(collection, offset, max); } // step four - retyping // (It would be nice to do this earlier so as to not have all the baggage // of unneeded attributes) if (query.getPropertyNames() != Query.ALL_NAMES) { // rebuild the type and wrap the reader SimpleFeatureType schema = collection.getSchema(); SimpleFeatureType target = SimpleFeatureTypeBuilder.retype(schema, query.getPropertyNames()); if (!target.equals(schema)) { collection = new ReTypingFeatureCollection(collection, target); } } return collection; } Envelope getEnvelope(Filter filter) { Envelope result = new Envelope(); if (filter instanceof And) { Envelope bounds = new Envelope(); for (Iterator iter = ((And) filter).getChildren().iterator(); iter.hasNext(); ) { Filter f = (Filter) iter.next(); Envelope e = getEnvelope(f); if (e == null) { return null; } else { bounds.expandToInclude(e); } } result = bounds; } else if (filter instanceof BinarySpatialOperator) { BinarySpatialOperator gf = (BinarySpatialOperator) filter; if (supportedFilterTypes.contains(gf.getClass())) { Expression lg = gf.getExpression1(); Expression rg = gf.getExpression2(); if (lg instanceof Literal) { Geometry g = (Geometry) ((Literal) lg).getValue(); if (rg instanceof PropertyName) { result = g.getEnvelopeInternal(); } } else if (rg instanceof Literal) { Geometry g = (Geometry) ((Literal) rg).getValue(); if (lg instanceof PropertyName) { result = g.getEnvelopeInternal(); } } } } return result; } public ResourceInfo getInfo() { return null; } public Name getName() { return contents.getSchema().getName(); } public QueryCapabilities getQueryCapabilities() { return new QueryCapabilities() { @Override public boolean isOffsetSupported() { return true; } }; } public Set getSupportedHints() { HashSet hints = new HashSet(); return hints; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy