/*
* 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.regroup;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.sis.feature.AbstractOperation;
import org.apache.sis.feature.SingleAttributeTypeBuilder;
import org.apache.sis.feature.builder.AttributeRole;
import org.apache.sis.feature.builder.FeatureTypeBuilder;
import org.apache.sis.internal.feature.AttributeConvention;
import org.geotoolkit.data.FeatureCollection;
import org.geotoolkit.data.FeatureIterator;
import org.geotoolkit.processing.AbstractProcess;
import org.opengis.feature.AttributeType;
import org.opengis.feature.Feature;
import org.opengis.feature.FeatureType;
import org.opengis.feature.PropertyType;
import org.opengis.parameter.ParameterValueGroup;
import org.opengis.util.GenericName;
import static org.geotoolkit.processing.vector.regroup.RegroupDescriptor.*;
import static org.geotoolkit.parameter.Parameters.*;
/**
* Regroup features and there geometries on a specify attribute name. Each different values of this
* attribute generate a Feature.
* @author Quentin Boileau
* @module
*/
public class RegroupProcess extends AbstractProcess {
/**
* Default constructor
*/
public RegroupProcess(final ParameterValueGroup input) {
super(INSTANCE,input);
}
/**
* {@inheritDoc }
*/
@Override
protected void execute() {
final FeatureCollection inputFeatureList = value(FEATURE_IN, inputParameters);
final String inputAttributeName = value(REGROUP_ATTRIBUTE, inputParameters);
final String inputGeometryName = value(GEOMETRY_NAME, inputParameters);
final FeatureCollection resultFeatureList = new RegroupFeatureCollection(inputFeatureList, inputAttributeName, inputGeometryName);
getOrCreate(FEATURE_OUT, outputParameters).setValue(resultFeatureList);
}
/**
* Create a new FeatureType with only the attribute and the geometry specified in process input.
*
* @param geometryName if null we use the default Feature geometry
*/
static FeatureType regroupFeatureType(final FeatureType oldFeatureType, String geometryName, final String regroupAttribute) {
final FeatureTypeBuilder ftb = new FeatureTypeBuilder(oldFeatureType);
//if keepedGeometry is null we use the default Geometry
if (geometryName == null) {
geometryName = AttributeConvention.GEOMETRY_PROPERTY.toString();
}
PropertyType property = oldFeatureType.getProperty(geometryName);
if(property instanceof AbstractOperation){
final Set<String> deps = ((AbstractOperation)property).getDependencies();
if(deps.size()==1){
geometryName = deps.iterator().next();
}
}
ftb.properties().clear();
ftb.addAttribute(String.class).setName(AttributeConvention.IDENTIFIER_PROPERTY);
for(PropertyType pt : oldFeatureType.getProperties(true)){
if(AttributeConvention.isGeometryAttribute(pt)){
if(pt.getName().toString().equals(geometryName)){
ftb.addAttribute((AttributeType) pt).addRole(AttributeRole.DEFAULT_GEOMETRY);
}
}else if(pt.getName().toString().equals(regroupAttribute)){
ftb.addProperty(pt);
}
}
return ftb.build();
}
/**
* Create a Feature with one of attribute values and an union of all features geometry with the
* same attribute value.
*
* @param regroupAttribute attribute specified in process input
* @param attrubuteValue one value of the specified attribute
* @param newFeatureType the new FeatureTYpe
* @param geometryName if null we use the default Feature geometry
* @param filtredList the input FeatureCollection filtered on attribute value
*/
static Feature regroupFeature(final String regroupAttribute, final Object attributeValue,
final FeatureType newFeatureType, String geometryName, final FeatureCollection filtredList)
{
final List<Geometry> geoms = new ArrayList<>();
try (final FeatureIterator featureIter = filtredList.iterator()) {
while (featureIter.hasNext()) {
final Feature feature = featureIter.next();
if (geometryName == null) {
geometryName = AttributeConvention.GEOMETRY_PROPERTY.toString();
}
for (final PropertyType property : feature.getType().getProperties(true)) {
//if property is a geometry
if (AttributeConvention.isGeometryAttribute(property)) {
//if it's the property we needed
final String name = property.getName().tip().toString();
if (name.equals(geometryName)) {
Geometry candidate = (Geometry) feature.getPropertyValue(name);
geoms.add(candidate);
}
}
}
}
}
Geometry regroupGeometry = new GeometryFactory().buildGeometry(geoms);
Feature resultFeature;
//In case
if (regroupAttribute == null && attributeValue == null) {
resultFeature = newFeatureType.newInstance();
resultFeature.setPropertyValue(AttributeConvention.IDENTIFIER_PROPERTY.toString(), "groupedGeometryFeature");
resultFeature.setPropertyValue(geometryName, regroupGeometry);
} else {
//result feature
resultFeature = newFeatureType.newInstance();
resultFeature.setPropertyValue(AttributeConvention.IDENTIFIER_PROPERTY.toString(), regroupAttribute + "-" + attributeValue);
resultFeature.setPropertyValue(regroupAttribute, attributeValue);
resultFeature.setPropertyValue(geometryName, regroupGeometry);
}
return resultFeature;
}
/**
* Browse in input FeatureCollection all different values of the specified attribute
* If regroupAttribute is null, we return an empty Collection.
*/
static Collection<Object> getAttributeValues(final String regroupAttribute, final FeatureCollection featureList) {
final Collection<Object> values = new ArrayList<>();
if (regroupAttribute != null) {
try (final FeatureIterator featureIter = featureList.iterator()) {
while (featureIter.hasNext()) {
final Feature feature = featureIter.next();
final Object value = feature.getPropertyValue(regroupAttribute);
if (!values.contains(value)) {
values.add(value);
}
}
}
}
return values;
}
}