You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2023/04/15 15:51:38 UTC
[sis] 04/04: If the resources to aggregate are instances of `MemoryGridResource`, aggregate directly the underlying `GridCoverage` instances.
This is an automated email from the ASF dual-hosted git repository.
desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git
commit 0e2089b1900656085bf926a2fe60ebeaf7363bc7
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Sat Apr 15 17:50:45 2023 +0200
If the resources to aggregate are instances of `MemoryGridResource`,
aggregate directly the underlying `GridCoverage` instances.
---
.../aggregate/BandAggregateGridResource.java | 39 ++++++++++++++--
.../sis/storage/aggregate/CoverageAggregator.java | 52 ++++++++++++++++++----
.../aggregate/BandAggregateGridResourceTest.java | 34 ++++++++++++--
3 files changed, 110 insertions(+), 15 deletions(-)
diff --git a/storage/sis-storage/src/main/java/org/apache/sis/storage/aggregate/BandAggregateGridResource.java b/storage/sis-storage/src/main/java/org/apache/sis/storage/aggregate/BandAggregateGridResource.java
index f7d502f9b8..301f28a259 100644
--- a/storage/sis-storage/src/main/java/org/apache/sis/storage/aggregate/BandAggregateGridResource.java
+++ b/storage/sis-storage/src/main/java/org/apache/sis/storage/aggregate/BandAggregateGridResource.java
@@ -28,13 +28,14 @@ import org.apache.sis.coverage.grid.GridCoverageProcessor;
import org.apache.sis.coverage.grid.IllegalGridGeometryException;
import org.apache.sis.internal.coverage.MultiSourceArgument;
import org.apache.sis.internal.coverage.RangeArgument;
+import org.apache.sis.internal.storage.MetadataBuilder;
+import org.apache.sis.internal.storage.MemoryGridResource;
import org.apache.sis.storage.Resource;
import org.apache.sis.storage.GridCoverageResource;
import org.apache.sis.storage.AbstractGridCoverageResource;
import org.apache.sis.storage.RasterLoadingStrategy;
import org.apache.sis.storage.DataStoreException;
import org.apache.sis.storage.event.StoreListeners;
-import org.apache.sis.internal.storage.MetadataBuilder;
import org.apache.sis.internal.util.UnmodifiableArrayList;
import org.apache.sis.util.collection.BackingStoreException;
@@ -139,7 +140,7 @@ final class BandAggregateGridResource extends AbstractGridCoverageResource imple
* @param parentListeners listeners of the parent resource, or {@code null} if none.
* @param sources resources whose bands shall be aggregated, in order. At least one resource must be provided.
* @param bandsPerSource sample dimensions for each source. May be {@code null} or may contain {@code null} elements.
- * @param processor the processor to use for creating grid coverages, or {@code null} for a default processor.
+ * @param processor the processor to use for creating grid coverages.
* @throws DataStoreException if an error occurred while fetching the grid geometry or sample dimensions from a resource.
* @throws IllegalGridGeometryException if a grid geometry is not compatible with the others.
* @throws IllegalArgumentException if some band indices are duplicated or outside their range of validity.
@@ -157,7 +158,7 @@ final class BandAggregateGridResource extends AbstractGridCoverageResource imple
this.gridGeometry = aggregate.domain(BandAggregateGridResource::domain);
this.sampleDimensions = List.copyOf(aggregate.ranges());
this.bandsPerSource = aggregate.bandsPerSource(false);
- this.processor = (processor != null) ? processor : new GridCoverageProcessor();
+ this.processor = processor;
} catch (BackingStoreException e) {
throw e.unwrapOrRethrow(DataStoreException.class);
}
@@ -201,6 +202,38 @@ final class BandAggregateGridResource extends AbstractGridCoverageResource imple
}
}
+ /**
+ * Creates a new range aggregation of grid coverage resources,
+ * potentially unwrapping in-memory resources for efficiency.
+ *
+ * @param parentListeners listeners of the parent resource, or {@code null} if none.
+ * @param sources resources whose bands shall be aggregated, in order. At least one resource must be provided.
+ * @param bandsPerSource sample dimensions for each source. May be {@code null} or may contain {@code null} elements.
+ * @param processor the processor to use for creating grid coverages.
+ * @return the band aggregated grid resource.
+ * @throws DataStoreException if an error occurred while fetching the grid geometry or sample dimensions from a resource.
+ * @throws IllegalGridGeometryException if a grid geometry is not compatible with the others.
+ * @throws IllegalArgumentException if some band indices are duplicated or outside their range of validity.
+ */
+ static GridCoverageResource create(final StoreListeners parentListeners,
+ final GridCoverageResource[] sources, final int[][] bandsPerSource,
+ final GridCoverageProcessor processor) throws DataStoreException
+ {
+ GridCoverageResource source = sources[0];
+ if (source instanceof MemoryGridResource) {
+ final var coverages = new GridCoverage[sources.length];
+ int i = 0;
+ do {
+ coverages[i] = ((MemoryGridResource) source).coverage;
+ if (++i >= sources.length) {
+ GridCoverage coverage = processor.aggregateRanges(coverages, bandsPerSource);
+ return new MemoryGridResource(parentListeners, coverage);
+ }
+ } while ((source = sources[i]) instanceof MemoryGridResource);
+ }
+ return new BandAggregateGridResource(parentListeners, sources, bandsPerSource, processor);
+ }
+
/** Not applicable to this implementation. */
@Override public Resource apply(MergeStrategy strategy) {return this;}
diff --git a/storage/sis-storage/src/main/java/org/apache/sis/storage/aggregate/CoverageAggregator.java b/storage/sis-storage/src/main/java/org/apache/sis/storage/aggregate/CoverageAggregator.java
index edd4825342..828c045584 100644
--- a/storage/sis-storage/src/main/java/org/apache/sis/storage/aggregate/CoverageAggregator.java
+++ b/storage/sis-storage/src/main/java/org/apache/sis/storage/aggregate/CoverageAggregator.java
@@ -132,7 +132,7 @@ public final class CoverageAggregator extends Group<GroupBySample> {
private GridCoverageProcessor processor;
/**
- * Creates an initially empty aggregator with no listeners and a default grid coverage processor.
+ * Creates an initially empty aggregator with no listeners.
*
* @since 1.4
*/
@@ -141,7 +141,7 @@ public final class CoverageAggregator extends Group<GroupBySample> {
}
/**
- * Creates an initially empty aggregator.
+ * Creates an initially empty aggregator with the given listeners.
*
* @param listeners listeners of the parent resource, or {@code null} if none.
* This is usually the listeners of the {@link org.apache.sis.storage.DataStore}.
@@ -151,6 +151,18 @@ public final class CoverageAggregator extends Group<GroupBySample> {
aggregates = new HashMap<>();
}
+ /**
+ * Creates an initially empty aggregator with the given listeners and coverage processor.
+ *
+ * @param listeners listeners of the parent resource, or {@code null} if none.
+ * @param processor the processor to use if an operation needs to be applied on coverages,
+ * or {@code null} for a default processor.
+ */
+ CoverageAggregator(final StoreListeners listeners, final GridCoverageProcessor processor) {
+ this(listeners);
+ this.processor = processor;
+ }
+
/**
* Creates a name for this group for use in metadata (not a persistent identifier).
* This is used only if this aggregator find resources having different sample dimensions.
@@ -295,12 +307,32 @@ public final class CoverageAggregator extends Group<GroupBySample> {
* This method combines homogeneous grid coverage resources by "stacking" their sample dimensions (bands).
* The grid geometry is typically the same for all resources, but some variations described below are allowed.
* The number of sample dimensions in the aggregated coverage is the sum of the number of sample dimensions in
- * each individual resource, unless a subset of sample dimensions is specified.
+ * each individual resource.
+ *
+ * <p>This convenience method delegates to {@link #addRangeAggregate(GridCoverageResource[], int[][])}.
+ * See that method for more information on restrictions.</p>
+ *
+ * @param sources resources whose bands shall be aggregated, in order.
+ * @throws DataStoreException if an error occurred while fetching the grid geometry or sample dimensions from a resource.
+ * @throws IllegalGridGeometryException if a grid geometry is not compatible with the others.
*
- * <p>The {@code bandsPerSource} argument specifies the bands to select in each resource.
- * That array can be {@code null} for selecting all bands in all resources,
- * or may contain {@code null} elements for selecting all bands of the corresponding resource.
- * An empty array element (i.e. zero band to select) discards the corresponding resource.</p>
+ * @see #getColorizer()
+ * @see GridCoverageProcessor#aggregateRanges(GridCoverage...)
+ *
+ * @since 1.4
+ */
+ public void addRangeAggregate(final GridCoverageResource... sources) throws DataStoreException {
+ addRangeAggregate(sources, (int[][]) null);
+ }
+
+ /**
+ * Adds a resource whose range is the aggregation of the specified bands of a sequence of resources.
+ * This method performs the same work than {@link #addRangeAggregate(GridCoverageResource...)},
+ * but with the possibility to specify the sample dimensions to retain in each source coverage.
+ * The {@code bandsPerSource} argument specifies the sample dimensions to keep, in order.
+ * That array can be {@code null} for selecting all sample dimensions in all source coverages,
+ * or may contain {@code null} elements for selecting all sample dimensions of the corresponding coverage.
+ * An empty array element (i.e. zero sample dimension to select) discards the corresponding source coverage.
*
* <h4>Restrictions</h4>
* <ul>
@@ -314,7 +346,7 @@ public final class CoverageAggregator extends Group<GroupBySample> {
*
* Some of those restrictions may be relaxed in future Apache SIS versions.
*
- * @param sources resources whose bands shall be aggregated, in order. At least one resource must be provided.
+ * @param sources resources whose bands shall be aggregated, in order.
* @param bandsPerSource sample dimensions for each source. May be {@code null} or may contain {@code null} elements.
* @throws DataStoreException if an error occurred while fetching the grid geometry or sample dimensions from a resource.
* @throws IllegalGridGeometryException if a grid geometry is not compatible with the others.
@@ -326,7 +358,9 @@ public final class CoverageAggregator extends Group<GroupBySample> {
* @since 1.4
*/
public void addRangeAggregate(final GridCoverageResource[] sources, final int[][] bandsPerSource) throws DataStoreException {
- add(new BandAggregateGridResource(listeners, sources, bandsPerSource, processor()));
+ if (sources.length != 0) {
+ add(BandAggregateGridResource.create(listeners, sources, bandsPerSource, processor()));
+ }
}
/**
diff --git a/storage/sis-storage/src/test/java/org/apache/sis/storage/aggregate/BandAggregateGridResourceTest.java b/storage/sis-storage/src/test/java/org/apache/sis/storage/aggregate/BandAggregateGridResourceTest.java
index a1669ab993..9af75669e8 100644
--- a/storage/sis-storage/src/test/java/org/apache/sis/storage/aggregate/BandAggregateGridResourceTest.java
+++ b/storage/sis-storage/src/test/java/org/apache/sis/storage/aggregate/BandAggregateGridResourceTest.java
@@ -30,6 +30,7 @@ import org.apache.sis.coverage.grid.GridExtent;
import org.apache.sis.coverage.grid.GridGeometry;
import org.apache.sis.coverage.grid.GridCoverage;
import org.apache.sis.coverage.grid.BufferedGridCoverage;
+import org.apache.sis.coverage.grid.GridCoverageProcessor;
import org.apache.sis.internal.storage.MemoryGridResource;
import org.apache.sis.storage.DataStoreException;
import org.apache.sis.storage.GridCoverageResource;
@@ -59,10 +60,16 @@ public final class BandAggregateGridResourceTest extends TestCase {
*/
private final GridGeometry domain;
+ /**
+ * The processor to give to {@link BandAggregateGridResource} constructor.
+ */
+ private final GridCoverageProcessor processor;
+
/**
* Creates a new test case.
*/
public BandAggregateGridResourceTest() {
+ processor = new GridCoverageProcessor();
domain = new GridGeometry(new GridExtent(WIDTH, HEIGHT), PixelInCell.CELL_CENTER,
MathTransforms.identity(2), HardCodedCRS.WGS84);
}
@@ -75,8 +82,8 @@ public final class BandAggregateGridResourceTest extends TestCase {
* @throws DataStoreException if an error occurred while fetching the grid geometry or sample dimensions from a resource.
* @throws IllegalGridGeometryException if a grid geometry is not compatible with the others.
*/
- private static BandAggregateGridResource create(final GridCoverageResource... sources) throws DataStoreException {
- return new BandAggregateGridResource(null, sources, null, null);
+ private BandAggregateGridResource create(final GridCoverageResource... sources) throws DataStoreException {
+ return new BandAggregateGridResource(null, sources, null, processor);
}
/**
@@ -120,7 +127,7 @@ public final class BandAggregateGridResourceTest extends TestCase {
final LocalName testName = Names.createLocalName(null, null, "test-name");
aggregation = new BandAggregateGridResource(null,
new GridCoverageResource[] {firstAndSecondBands, thirdAndFourthBands, fifthAndSixthBands},
- new int[][] {null, new int[] {1, 0}, new int[] {1}}, null);
+ new int[][] {null, new int[] {1, 0}, new int[] {1}}, processor);
aggregation.setIdentifier(testName);
assertEquals(testName, aggregation.getIdentifier().orElse(null));
@@ -128,6 +135,27 @@ public final class BandAggregateGridResourceTest extends TestCase {
assertAllPixelsEqual(aggregation.read(null, 2, 4), 104, 106);
}
+ /**
+ * Tests aggregation of resources using {@link CoverageAggregator}.
+ *
+ * @throws DataStoreException if an error occurred while reading a resource.
+ */
+ @Test
+ public void usingCoverageAggregator() throws DataStoreException {
+ final GridCoverageResource first = singleValuePerBand(17);
+ final GridCoverageResource second = singleValuePerBand(23);
+ final var aggregator = new CoverageAggregator(null, processor);
+ aggregator.addRangeAggregate(first, second);
+ /*
+ * If the result is not an instance of `MemoryGridResource`,
+ * this is a bug in `BandAggregateGridResource.create(…)`.
+ */
+ final var aggregation = (MemoryGridResource) aggregator.build(null);
+ assertAllPixelsEqual(aggregation.read(null), 17, 23);
+ assertAllPixelsEqual(aggregation.read(null, 0), 17);
+ assertAllPixelsEqual(aggregation.read(null, 1), 23);
+ }
+
/**
* Creates a new grid coverage resource with bands having the given values.
* The length of the {@code bandValues} array is the number of bands to create.