From: <svn...@os...> - 2012-04-15 22:29:55
|
Author: aaime Date: 2012-04-15 15:29:46 -0700 (Sun, 15 Apr 2012) New Revision: 38663 Added: trunk/modules/unsupported/process-feature/src/main/java/org/geotools/process/feature/gs/CentroidProcess.java trunk/modules/unsupported/process-feature/src/main/java/org/geotools/process/feature/gs/ProcessingCollection.java trunk/modules/unsupported/process-feature/src/main/java/org/geotools/process/feature/gs/SimpleProcessingCollection.java trunk/modules/unsupported/process-feature/src/test/java/org/geotools/process/feature/gs/CentroidProcessTest.java Modified: trunk/modules/unsupported/process-feature/src/main/java/org/geotools/process/feature/gs/BufferFeatureCollection.java trunk/modules/unsupported/process-feature/src/main/java/org/geotools/process/feature/gs/FeatureGSProcessFactory.java trunk/modules/unsupported/process-feature/src/test/java/org/geotools/process/feature/gs/BufferFeatureCollectionTest.java Log: [GEOT-3948] New WPS process: org.geotools.process.features.gs.CentroidProcess by Rohan Singh, plus some base class improvements and tests by yours truly Modified: trunk/modules/unsupported/process-feature/src/main/java/org/geotools/process/feature/gs/BufferFeatureCollection.java =================================================================== --- trunk/modules/unsupported/process-feature/src/main/java/org/geotools/process/feature/gs/BufferFeatureCollection.java 2012-04-12 14:29:44 UTC (rev 38662) +++ trunk/modules/unsupported/process-feature/src/main/java/org/geotools/process/feature/gs/BufferFeatureCollection.java 2012-04-15 22:29:46 UTC (rev 38663) @@ -32,6 +32,7 @@ import org.geotools.feature.simple.SimpleFeatureBuilder; import org.geotools.feature.simple.SimpleFeatureTypeBuilder; import org.geotools.feature.type.GeometryTypeImpl; +import org.geotools.geometry.jts.ReferencedEnvelope; import org.geotools.util.Converters; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; @@ -86,20 +87,43 @@ /** * Wrapper that will trigger the buffer computation as features are requested */ - static class BufferedFeatureCollection extends DecoratingSimpleFeatureCollection { + static class BufferedFeatureCollection extends SimpleProcessingCollection { Double distance; String attribute; + + SimpleFeatureCollection delegate; - SimpleFeatureType schema; - public BufferedFeatureCollection(SimpleFeatureCollection delegate, String attribute, Double distance) { - super(delegate); this.distance = distance; this.attribute = attribute; + this.delegate = delegate; + + } + + @Override + public SimpleFeatureIterator features() { + return new BufferedFeatureIterator(delegate, this.attribute, this.distance, getSchema()); + } + + @Override + public ReferencedEnvelope getBounds() { + if(attribute == null) { + // in this case we just have to expand the original collection bounds + ReferencedEnvelope re = delegate.getBounds(); + re.expandBy(distance); + return re; + } else { + // unlucky case, we need to actually compute by hand... + return getFeatureBounds(); + } + } + + @Override + protected SimpleFeatureType buildTargetFeatureType() { // create schema SimpleFeatureTypeBuilder tb = new SimpleFeatureTypeBuilder(); for (AttributeDescriptor descriptor : delegate.getSchema().getAttributeDescriptors()) { @@ -120,30 +144,15 @@ tb.setDescription(delegate.getSchema().getDescription()); tb.setCRS(delegate.getSchema().getCoordinateReferenceSystem()); tb.setName(delegate.getSchema().getName()); - this.schema = tb.buildFeatureType(); + return tb.buildFeatureType(); } @Override - public SimpleFeatureIterator features() { - return new BufferedFeatureIterator(delegate, this.attribute, this.distance, getSchema()); + public int size() { + return delegate.size(); } - @Override - public Iterator<SimpleFeature> iterator() { - return new WrappingIterator(features()); - } - - @Override - public void close(Iterator<SimpleFeature> close) { - if (close instanceof WrappingIterator) { - ((WrappingIterator) close).close(); - } - } - - @Override - public SimpleFeatureType getSchema() { - return this.schema; - } + } /** Added: trunk/modules/unsupported/process-feature/src/main/java/org/geotools/process/feature/gs/CentroidProcess.java =================================================================== --- trunk/modules/unsupported/process-feature/src/main/java/org/geotools/process/feature/gs/CentroidProcess.java (rev 0) +++ trunk/modules/unsupported/process-feature/src/main/java/org/geotools/process/feature/gs/CentroidProcess.java 2012-04-15 22:29:46 UTC (rev 38663) @@ -0,0 +1,137 @@ +/* + * GeoTools - The Open Source Java GIS Toolkit + * http://geotools.org + * + * (C) 2011, Open Source Geospatial Foundation (OSGeo) + * (C) 2001-2007 TOPP - www.openplans.org. + * + * 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.process.feature.gs; + +import java.util.NoSuchElementException; + +import org.geotools.data.DataUtilities; +import org.geotools.data.simple.SimpleFeatureCollection; +import org.geotools.data.simple.SimpleFeatureIterator; +import org.geotools.feature.simple.SimpleFeatureBuilder; +import org.geotools.feature.simple.SimpleFeatureTypeBuilder; +import org.geotools.geometry.jts.ReferencedEnvelope; +import org.geotools.process.ProcessException; +import org.geotools.process.factory.DescribeParameter; +import org.geotools.process.factory.DescribeProcess; +import org.geotools.process.factory.DescribeResult; +import org.geotools.process.gs.GSProcess; +import org.opengis.feature.simple.SimpleFeature; +import org.opengis.feature.simple.SimpleFeatureType; +import org.opengis.feature.type.AttributeDescriptor; +import org.opengis.feature.type.GeometryDescriptor; + +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.Point; + +/** + * A process that returns the centroids for the geometries in the + * input feature collection. + * + * @author Rohan Singh + * + * + * @source $URL: http://svn.osgeo.org/geotools/trunk/modules/unsupported/process-feature/src/main/java/org/geotools/process/feature/gs/CentroidProcess.java $ + */ +@DescribeProcess(title = "centroid", description = "Returns centroids of the geometries in the feature collection") +public class CentroidProcess implements GSProcess { + + @DescribeResult(name = "result", description = "The feature collection with centroids") + public SimpleFeatureCollection execute( + @DescribeParameter(name = "features", description = "The feature collection to get centroids for") SimpleFeatureCollection features) + throws ProcessException { + return DataUtilities.simple(new CentroidFeatureCollection(features)); + } + + static class CentroidFeatureCollection extends SimpleProcessingCollection { + SimpleFeatureCollection delegate; + + public CentroidFeatureCollection(SimpleFeatureCollection delegate) { + this.delegate = delegate; + } + + @Override + public SimpleFeatureIterator features() { + return new CentroidFeatureIterator(delegate.features(), getSchema()); + } + + @Override + public ReferencedEnvelope getBounds() { + return getFeatureBounds(); + } + + @Override + protected SimpleFeatureType buildTargetFeatureType() { + SimpleFeatureTypeBuilder tb = new SimpleFeatureTypeBuilder(); + for (AttributeDescriptor ad : delegate.getSchema().getAttributeDescriptors()) { + if(ad instanceof GeometryDescriptor) { + GeometryDescriptor gd = (GeometryDescriptor) ad; + Class<?> binding = ad.getType().getBinding(); + if(Point.class.isAssignableFrom(binding)) { + tb.add(ad); + } else { + tb.minOccurs(ad.getMinOccurs()); + tb.maxOccurs(ad.getMaxOccurs()); + tb.nillable(ad.isNillable()); + tb.add(ad.getLocalName(), Point.class, gd.getCoordinateReferenceSystem()); + } + } else { + tb.add(ad); + } + } + tb.setName(delegate.getSchema().getName()); + return tb.buildFeatureType(); + } + + @Override + public int size() { + return delegate.size(); + } + } + + static class CentroidFeatureIterator implements SimpleFeatureIterator { + SimpleFeatureIterator delegate; + + SimpleFeatureBuilder fb; + + public CentroidFeatureIterator(SimpleFeatureIterator delegate, SimpleFeatureType schema) { + this.delegate = delegate; + fb = new SimpleFeatureBuilder(schema); + } + + public void close() { + delegate.close(); + } + + public boolean hasNext() { + return delegate.hasNext(); + } + + public SimpleFeature next() throws NoSuchElementException { + SimpleFeature f = delegate.next(); + for (Object attribute : f.getAttributes()) { + if ((attribute instanceof Geometry) && + !(attribute instanceof Point)) { + attribute = ((Geometry) attribute).getCentroid(); + } + fb.add(attribute); + } + return fb.buildFeature(f.getID()); + } + + } +} Modified: trunk/modules/unsupported/process-feature/src/main/java/org/geotools/process/feature/gs/FeatureGSProcessFactory.java =================================================================== --- trunk/modules/unsupported/process-feature/src/main/java/org/geotools/process/feature/gs/FeatureGSProcessFactory.java 2012-04-12 14:29:44 UTC (rev 38662) +++ trunk/modules/unsupported/process-feature/src/main/java/org/geotools/process/feature/gs/FeatureGSProcessFactory.java 2012-04-15 22:29:46 UTC (rev 38663) @@ -5,6 +5,7 @@ import org.geotools.process.feature.gs.AggregateProcess; import org.geotools.process.feature.gs.BoundsProcess; import org.geotools.process.feature.gs.BufferFeatureCollection; +import org.geotools.process.feature.gs.CentroidProcess; import org.geotools.process.feature.gs.ClipProcess; import org.geotools.process.feature.gs.CollectGeometries; import org.geotools.process.feature.gs.CountProcess; @@ -42,6 +43,7 @@ AggregateProcess.class, BoundsProcess.class, BufferFeatureCollection.class, + CentroidProcess.class, ClipProcess.class, CollectGeometries.class, CountProcess.class, Added: trunk/modules/unsupported/process-feature/src/main/java/org/geotools/process/feature/gs/ProcessingCollection.java =================================================================== --- trunk/modules/unsupported/process-feature/src/main/java/org/geotools/process/feature/gs/ProcessingCollection.java (rev 0) +++ trunk/modules/unsupported/process-feature/src/main/java/org/geotools/process/feature/gs/ProcessingCollection.java 2012-04-15 22:29:46 UTC (rev 38663) @@ -0,0 +1,434 @@ +/* + * GeoTools - The Open Source Java GIS Toolkit + * http://geotools.org + * + * (C) 2011, Open Source Geospatial Foundation (OSGeo) + * (C) 2001-2007 TOPP - www.openplans.org. + * + * 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.process.feature.gs; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.UUID; + +import org.geotools.data.DataUtilities; +import org.geotools.data.store.FilteringFeatureCollection; +import org.geotools.feature.CollectionListener; +import org.geotools.feature.FeatureCollection; +import org.geotools.feature.FeatureIterator; +import org.geotools.feature.collection.SortedSimpleFeatureCollection; +import org.geotools.geometry.jts.ReferencedEnvelope; +import org.geotools.util.NullProgressListener; +import org.opengis.feature.Feature; +import org.opengis.feature.FeatureVisitor; +import org.opengis.feature.simple.SimpleFeature; +import org.opengis.feature.simple.SimpleFeatureType; +import org.opengis.feature.type.FeatureType; +import org.opengis.filter.Filter; +import org.opengis.filter.sort.SortBy; +import org.opengis.util.ProgressListener; + +/** + * Abstract base class to ease the implementation of a streaming processing collection, that is, one + * that tries to compute the results on the fly as the iterator is traversed. + * + * Besides the few methods that the implementor actually needs to override it suggested to consider + * overriding also the followings to get extra performance gains: + * <ul> + * {@link #subCollection(Filter)} {@link #sort(SortBy)} + * </ul> + * + * @author Andrea Aime - GeoSolutions + * + * @param <T> + * @param <F> + */ +public abstract class ProcessingCollection<T extends FeatureType, F extends Feature> + implements FeatureCollection<T, F> { + + private static final String READ_ONLY_ERROR = "This collection is read only"; + + private T schema; + + private String id; + + public ProcessingCollection() { + id = getClass().getSimpleName() + "-" + UUID.randomUUID().toString(); + } + + /** + * Streams out the output features + */ + @Override + public abstract FeatureIterator<F> features(); + + @Override + public void accepts(FeatureVisitor visitor, ProgressListener progress) throws IOException { + FeatureIterator<F> iterator = null; + float size = progress != null ? size() : 0; + if (progress == null) { + progress = new NullProgressListener(); + } + try { + float position = 0; + progress.started(); + iterator = features(); + while (iterator.hasNext()) { + try { + F feature = iterator.next(); + visitor.visit(feature); + if (size > 0) { + progress.progress(position++ / size); + } + } catch (Exception erp) { + progress.exceptionOccurred(erp); + throw new IOException("Error occurred while iterating over features", erp); + } + } + } finally { + progress.complete(); + close(iterator); + } + + } + + /** + * Convenience implementation that just wraps this collection into a + * {@link FilteringFeatureCollection}. Subclasses might want to override this in case the filter + * can be cascaded to their data sources. + * + * @param filter + * @return + */ + @Override + public FeatureCollection<T, F> subCollection(Filter filter) { + return new FilteringFeatureCollection<T, F>(this, filter); + } + + /** + * Convenience implementation that + */ + @Override + public FeatureCollection<T, F> sort(SortBy order) { + if (schema instanceof SimpleFeatureType) { + // go for the most efficient way if possible, otherwise rely on pure in memory + // sorting... + return (FeatureCollection<T, F>) new SortedSimpleFeatureCollection( + DataUtilities + .simple((FeatureCollection<SimpleFeatureType, SimpleFeature>) this), + new SortBy[] { order }); + } else { + // hmm... we don't even have a basic non simple collection... need to implement one + // before + // going here + throw new UnsupportedOperationException("Cannot sort on complex features at the moment"); + } + } + + /** + * The bounds of features in the output. If the bounds are not known in advance once can call the + * getFeatureBounds() which will build it from the features as they are returned from the feature + * iterator. + */ + @Override + public abstract ReferencedEnvelope getBounds(); + + @Override + public Iterator<F> iterator() { + final FeatureIterator<F> features = features(); + if (features == null) { + return null; + } else { + return new WrappingIterator(features); + } + } + + /** + * Builds once and for all the target feature type. The results are available by calling getSchema() + * + * @return + */ + protected abstract T buildTargetFeatureType(); + + /** + * The number of features in the output. If the size is not known in advance once can call the + * getFeatureCount() which will count the features as they are returned from the feature + * iterator. + */ + @Override + public abstract int size(); + + /** + * Convenience method that counts features by traversing the feature iterator. + * + * @return + */ + protected int getFeatureCount() { + FeatureIterator<F> fi = null; + try { + fi = features(); + int count = 0; + while (fi.hasNext()) { + fi.next(); + count++; + } + return count; + } finally { + close(fi); + } + } + + /** + * Convenience method that computes the feature bounds by traversing the feature iterator. + * + * @return + */ + protected ReferencedEnvelope getFeatureBounds() { + FeatureIterator<F> fi = null; + try { + fi = features(); + ReferencedEnvelope bounds = null; + while (fi.hasNext()) { + F feature = fi.next(); + ReferencedEnvelope featureEnvelope = null; + if(feature != null && feature.getBounds() != null) { + featureEnvelope = ReferencedEnvelope.reference(feature.getBounds()); + } + + if(featureEnvelope != null) { + if(bounds == null) { + bounds = new ReferencedEnvelope(featureEnvelope); + } else { + bounds.expandToInclude(featureEnvelope); + } + } + } + + return bounds; + } finally { + close(fi); + } + } + + @Override + public void close(FeatureIterator<F> fi) { + if (fi != null) { + fi.close(); + } + } + + @Override + public void close(Iterator<F> close) { + if (close instanceof WrappingIterator) { + ((WrappingIterator) close).close(); + } + } + + /** + * An implementation that actually does not attach the listener, since the collection is not + * modifiable. Subclasses might want to override this. + */ + @Override + public void addListener(CollectionListener listener) throws NullPointerException { + // we just don't implement this, contents of the collection might be generated + // out of thin air and cannot be changed normally, subclasses may want to override + } + + @Override + public void removeListener(CollectionListener listener) throws NullPointerException { + // we just don't implement this, contents of the collection might be generated + // out of thin air and cannot be changed normally, subclasses may want to override + } + + @Override + public T getSchema() { + if(schema == null) { + schema = buildTargetFeatureType(); + } + + return schema; + } + + @Override + public String getID() { + return id; + } + + /** + * Empty as the collection is supposed to be empty anyways, but subclasses might want to + * override the method to get rid of whatever state they might be holding onto. + */ + @Override + public void purge() { + // nothing to do here + } + + @Override + public boolean add(F obj) { + throw new UnsupportedOperationException(READ_ONLY_ERROR); + } + + @Override + public boolean addAll(Collection<? extends F> collection) { + throw new UnsupportedOperationException(READ_ONLY_ERROR); + } + + @Override + public boolean addAll(FeatureCollection<? extends T, ? extends F> resource) { + throw new UnsupportedOperationException(READ_ONLY_ERROR); + } + + @Override + public void clear() { + throw new UnsupportedOperationException(READ_ONLY_ERROR); + } + + /** + * Returns <tt>true</tt> if this collection contains the specified element. <tt></tt>. + * <p> + * + * This implementation iterates over the elements in the collection, checking each element in + * turn for equality with the specified element. + * + * @param o object to be checked for containment in this collection. + * @return <tt>true</tt> if this collection contains the specified element. + */ + public boolean contains(Object o) { + Iterator<F> e = null; + try { + e = iterator(); + if (o == null) { + while (e.hasNext()) + if (e.next() == null) + return true; + } else { + while (e.hasNext()) + if (o.equals(e.next())) + return true; + } + return false; + } finally { + close(e); + } + } + + /** + * Returns <tt>true</tt> if this collection contains all of the elements in the specified + * collection. + * <p> + * + * @param c collection to be checked for containment in this collection. + * @return <tt>true</tt> if this collection contains all of the elements in the specified + * collection. + * @throws NullPointerException if the specified collection is null. + * + * @see #contains(Object) + */ + public boolean containsAll(Collection<?> c) { + Iterator<?> e = c.iterator(); + try { + while (e.hasNext()) + if (!contains(e.next())) + return false; + return true; + } finally { + if (c instanceof FeatureCollection) { + ((FeatureCollection) c).close(e); + } + } + } + + @Override + public boolean isEmpty() { + FeatureIterator<F> fi = null; + try { + fi = features(); + return !fi.hasNext(); + } finally { + close(fi); + } + } + + @Override + public boolean remove(Object o) { + throw new UnsupportedOperationException(READ_ONLY_ERROR); + } + + @Override + public boolean removeAll(Collection<?> c) { + throw new UnsupportedOperationException(READ_ONLY_ERROR); + } + + @Override + public boolean retainAll(Collection<?> c) { + throw new UnsupportedOperationException(READ_ONLY_ERROR); + } + + /** + * Utility to get all the features to implement the toArray methods + */ + protected List<F> toList() { + ArrayList<F> result = new ArrayList<F>(); + FeatureIterator<F> fi = null; + try { + fi = features(); + for (int i = 0; fi.hasNext(); i++) { + result.add(fi.next()); + } + return result; + } finally { + close(fi); + } + } + + public Object[] toArray() { + return toList().toArray(); + } + + @SuppressWarnings("unchecked") + public <T> T[] toArray(T[] a) { + return toList().toArray(a); + } + + /** + * Wraps a {@link FeatureIterator} into a standard {@link Iterator} + */ + private static class WrappingIterator<F extends Feature> implements Iterator<F> { + FeatureIterator<F> delegate; + + public WrappingIterator(FeatureIterator<F> delegate) { + super(); + this.delegate = delegate; + } + + public boolean hasNext() { + return delegate.hasNext(); + } + + public F next() { + return delegate.next(); + } + + public void remove() { + throw new UnsupportedOperationException(); + } + + public void close() { + delegate.close(); + } + } + +} Added: trunk/modules/unsupported/process-feature/src/main/java/org/geotools/process/feature/gs/SimpleProcessingCollection.java =================================================================== --- trunk/modules/unsupported/process-feature/src/main/java/org/geotools/process/feature/gs/SimpleProcessingCollection.java (rev 0) +++ trunk/modules/unsupported/process-feature/src/main/java/org/geotools/process/feature/gs/SimpleProcessingCollection.java 2012-04-15 22:29:46 UTC (rev 38663) @@ -0,0 +1,48 @@ +/* + * GeoTools - The Open Source Java GIS Toolkit + * http://geotools.org + * + * (C) 2011, Open Source Geospatial Foundation (OSGeo) + * (C) 2001-2007 TOPP - www.openplans.org. + * + * 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.process.feature.gs; + +import org.geotools.data.DataUtilities; +import org.geotools.data.simple.SimpleFeatureCollection; +import org.geotools.feature.collection.SortedSimpleFeatureCollection; +import org.opengis.feature.simple.SimpleFeature; +import org.opengis.feature.simple.SimpleFeatureType; +import org.opengis.filter.Filter; +import org.opengis.filter.sort.SortBy; + +/** + * The simple feature version of {@link ProcessingCollection}. Please see the base class for further + * information on how to implement a proper streaming processing collection on top of this base + * class + * + * @author Andrea Aime - GeoSolutions + * + */ +public abstract class SimpleProcessingCollection extends + ProcessingCollection<SimpleFeatureType, SimpleFeature> implements SimpleFeatureCollection { + + @Override + public SimpleFeatureCollection sort(SortBy order) { + return new SortedSimpleFeatureCollection(this, new SortBy[] { order }); + } + + @Override + public SimpleFeatureCollection subCollection(Filter filter) { + return DataUtilities.simple(super.subCollection(filter)); + } +} Modified: trunk/modules/unsupported/process-feature/src/test/java/org/geotools/process/feature/gs/BufferFeatureCollectionTest.java =================================================================== --- trunk/modules/unsupported/process-feature/src/test/java/org/geotools/process/feature/gs/BufferFeatureCollectionTest.java 2012-04-12 14:29:44 UTC (rev 38662) +++ trunk/modules/unsupported/process-feature/src/test/java/org/geotools/process/feature/gs/BufferFeatureCollectionTest.java 2012-04-15 22:29:46 UTC (rev 38663) @@ -19,12 +19,14 @@ import junit.framework.TestCase; +import org.geotools.data.collection.ListFeatureCollection; import org.geotools.data.simple.SimpleFeatureCollection; import org.geotools.data.simple.SimpleFeatureIterator; import org.geotools.factory.CommonFactoryFinder; import org.geotools.feature.DefaultFeatureCollection; import org.geotools.feature.simple.SimpleFeatureBuilder; import org.geotools.feature.simple.SimpleFeatureTypeBuilder; +import org.geotools.geometry.jts.ReferencedEnvelope; import org.opengis.feature.simple.SimpleFeature; import org.opengis.filter.FilterFactory; @@ -34,11 +36,6 @@ import com.vividsolutions.jts.geom.LinearRing; import com.vividsolutions.jts.geom.PrecisionModel; -/** - * - * - * @source $URL$ - */ public class BufferFeatureCollectionTest extends TestCase { FilterFactory ff = CommonFactoryFinder.getFilterFactory(null); @@ -69,6 +66,9 @@ SimpleFeature sf = iterator.next(); assertTrue(expected.equals((Geometry) sf.getDefaultGeometry())); } + + assertEquals(new ReferencedEnvelope(-500, 501, -500, 501, null), output.getBounds()); + assertEquals(2, output.size()); } public void testExecuteLineString() throws Exception { @@ -108,6 +108,9 @@ SimpleFeature sf = iterator.next(); assertTrue(expected.equals((Geometry) sf.getDefaultGeometry())); } + + assertEquals(new ReferencedEnvelope(-500, 507, -500, 507, null), output.getBounds()); + assertEquals(5, output.size()); } public void testExecutePolygon() throws Exception { @@ -152,6 +155,9 @@ SimpleFeature sf = iterator.next(); assertTrue(expected.equals((Geometry) sf.getDefaultGeometry())); } + + assertEquals(new ReferencedEnvelope(-500, 506, -500, 506, null), output.getBounds()); + assertEquals(5, output.size()); } public void testExecuteBufferAttribute() throws Exception { @@ -164,7 +170,7 @@ GeometryFactory gf = new GeometryFactory(); SimpleFeatureBuilder b = new SimpleFeatureBuilder(tb.buildFeatureType()); - DefaultFeatureCollection features = new DefaultFeatureCollection(null, b.getFeatureType()); + ListFeatureCollection features = new ListFeatureCollection(b.getFeatureType()); for (int numFeatures = 0; numFeatures < 5; numFeatures++) { Coordinate array[] = new Coordinate[4]; int j = 0; @@ -176,7 +182,7 @@ LinearRing shell = new LinearRing(array, new PrecisionModel(), 0); b.add(gf.createPolygon(shell, null)); b.add(0); - b.add(500); + b.add(numFeatures + 1); features.add(b.buildFeature(numFeatures + "")); } @@ -184,6 +190,7 @@ SimpleFeatureCollection output = process.execute(features, null, "buffer"); assertEquals(5, output.size()); SimpleFeatureIterator iterator = output.features(); + ReferencedEnvelope expectedBounds = new ReferencedEnvelope(output.getSchema().getCoordinateReferenceSystem()); for (int numFeatures = 0; numFeatures < 5; numFeatures++) { Coordinate[] array = new Coordinate[4]; int j = 0; @@ -193,10 +200,14 @@ } array[3] = new Coordinate(numFeatures, numFeatures); LinearRing shell = new LinearRing(array, new PrecisionModel(), 0); - Geometry expected = gf.createPolygon(shell, null).buffer(500); + Geometry expected = gf.createPolygon(shell, null).buffer(numFeatures + 1); + expectedBounds.expandToInclude(expected.getEnvelopeInternal()); SimpleFeature sf = iterator.next(); assertTrue(expected.equals((Geometry) sf.getDefaultGeometry())); } + + assertEquals(expectedBounds, output.getBounds()); + assertEquals(5, output.size()); } } Added: trunk/modules/unsupported/process-feature/src/test/java/org/geotools/process/feature/gs/CentroidProcessTest.java =================================================================== --- trunk/modules/unsupported/process-feature/src/test/java/org/geotools/process/feature/gs/CentroidProcessTest.java (rev 0) +++ trunk/modules/unsupported/process-feature/src/test/java/org/geotools/process/feature/gs/CentroidProcessTest.java 2012-04-15 22:29:46 UTC (rev 38663) @@ -0,0 +1,70 @@ +package org.geotools.process.feature.gs; + +import static junit.framework.Assert.*; + +import org.geotools.data.collection.ListFeatureCollection; +import org.geotools.data.simple.SimpleFeatureCollection; +import org.geotools.data.simple.SimpleFeatureIterator; +import org.geotools.feature.simple.SimpleFeatureBuilder; +import org.geotools.feature.simple.SimpleFeatureTypeBuilder; +import org.junit.Before; +import org.junit.Test; +import org.opengis.feature.simple.SimpleFeature; +import org.opengis.feature.simple.SimpleFeatureType; + +import com.vividsolutions.jts.geom.Point; +import com.vividsolutions.jts.geom.Polygon; +import com.vividsolutions.jts.io.WKTReader; + +public class CentroidProcessTest { + + WKTReader reader = new WKTReader(); + private ListFeatureCollection fc; + + @Before + public void setup() throws Exception { + SimpleFeatureTypeBuilder tb = new SimpleFeatureTypeBuilder(); + tb.add("geom", Polygon.class, "EPSG:4326"); + tb.add("name", String.class); + tb.setName("circles"); + SimpleFeatureType ft = tb.buildFeatureType(); + + fc = new ListFeatureCollection(ft); + + SimpleFeatureBuilder fb = new SimpleFeatureBuilder(ft); + fb.add(reader.read("POINT(0 0)").buffer(10)); + fb.add("one"); + fc.add(fb.buildFeature(null)); + fb.add(reader.read("POINT(10 0)").buffer(10)); + fb.add("two"); + fc.add(fb.buildFeature(null)); + } + + @Test + public void testSchema() { + CentroidProcess cp = new CentroidProcess(); + SimpleFeatureCollection result = cp.execute(fc); + SimpleFeatureType ft = result.getSchema(); + assertEquals(2, ft.getAttributeCount()); + assertEquals(Point.class, ft.getGeometryDescriptor().getType().getBinding()); + assertEquals(String.class, ft.getDescriptor("name").getType().getBinding()); + } + + + @Test + public void testResults() throws Exception { + CentroidProcess cp = new CentroidProcess(); + SimpleFeatureCollection result = cp.execute(fc); + + SimpleFeatureIterator it = result.features(); + assertTrue(it.hasNext()); + SimpleFeature f = it.next(); + assertEquals(0, ((Point) f.getDefaultGeometry()).getX(), 1e-6); + assertEquals(0, ((Point) f.getDefaultGeometry()).getY(), 1e-6); + assertEquals("one", f.getAttribute("name")); + f = it.next(); + assertEquals(10, ((Point) f.getDefaultGeometry()).getX(), 1e-6); + assertEquals(0, ((Point) f.getDefaultGeometry()).getY(), 1e-6); + assertEquals("two", f.getAttribute("name")); + } +} |