/* * Geotoolkit - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2011, Geomatys * * 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.geotoolkit.processing.vector.nearest; import com.vividsolutions.jts.geom.Geometry; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import org.geotoolkit.data.FeatureCollection; import org.geotoolkit.data.FeatureIterator; import org.geotoolkit.data.query.Query; import org.geotoolkit.data.query.QueryBuilder; import org.geotoolkit.factory.FactoryFinder; import org.geotoolkit.factory.Hints; import org.geotoolkit.util.NamesExt; import org.geotoolkit.geometry.jts.JTS; import org.geotoolkit.processing.AbstractProcess; import org.geotoolkit.process.ProcessException; import org.geotoolkit.processing.vector.VectorProcessUtils; import org.apache.sis.storage.DataStoreException; import org.opengis.feature.Feature; import org.opengis.feature.PropertyType; import org.geotoolkit.processing.vector.VectorDescriptor; import org.opengis.filter.Filter; import org.opengis.filter.FilterFactory2; import org.opengis.filter.identity.Identifier; import org.opengis.geometry.MismatchedDimensionException; import org.opengis.parameter.ParameterValueGroup; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.operation.TransformException; import org.opengis.util.FactoryException; import org.apache.sis.feature.FeatureExt; import org.apache.sis.internal.feature.AttributeConvention; import static org.geotoolkit.parameter.Parameters.*; /** * Process return the nearest Feature(s) form a FeatureCollection to a geometry * * @author Quentin Boileau */ public class NearestProcess extends AbstractProcess { private static final FilterFactory2 FF = (FilterFactory2) FactoryFinder.getFilterFactory( new Hints(Hints.FILTER_FACTORY, FilterFactory2.class)); /** * Default constructor */ public NearestProcess(final ParameterValueGroup input) { super(NearestDescriptor.INSTANCE,input); } /** * {@inheritDoc } */ @Override protected void execute() throws ProcessException { try { final FeatureCollection inputFeatureList = value(VectorDescriptor.FEATURE_IN, inputParameters); final Geometry interGeom = value(NearestDescriptor.GEOMETRY_IN, inputParameters); final FeatureCollection resultFeatureList = new NearestFeatureCollection(inputFeatureList.subCollection(nearestQuery(inputFeatureList, interGeom))); getOrCreate(VectorDescriptor.FEATURE_OUT, outputParameters).setValue(resultFeatureList); } catch (FactoryException | DataStoreException | TransformException ex) { throw new ProcessException(ex.getMessage(), this, ex); } } /** * Create a query to filter nearest feature to the geometry * * @return nearest query filter */ private Query nearestQuery(final FeatureCollection original, final Geometry geom) throws FactoryException, MismatchedDimensionException, TransformException { CoordinateReferenceSystem geomCrs = JTS.findCoordinateReferenceSystem(geom); if (geomCrs == null) { geomCrs = FeatureExt.getCRS(original.getFeatureType()); } double dist = Double.POSITIVE_INFINITY; final Collection<Identifier> listID = new ArrayList<>(); try (final FeatureIterator iter = original.iterator(null)) { while (iter.hasNext()) { final Feature feature = iter.next(); for (final PropertyType property : feature.getType().getProperties(true)) { if (AttributeConvention.isGeometryAttribute(property)) { Geometry featureGeom = (Geometry) feature.getPropertyValue(property.getName().toString()); final CoordinateReferenceSystem featureGeomCRS = FeatureExt.getCRS(property); //re-project feature geometry into input geometry CRS featureGeom = VectorProcessUtils.repojectGeometry(geomCrs, featureGeomCRS, featureGeom); final double computedDist = geom.distance(featureGeom); if (computedDist < dist) { listID.clear(); dist = computedDist; listID.add(FeatureExt.getId(feature)); } else { if (computedDist == dist) { listID.add(FeatureExt.getId(feature)); } } } } } } final Filter filter = FF.id(new HashSet<>(listID)); return QueryBuilder.filtered("nearest", filter); } }