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 2019/10/27 16:25:31 UTC
[sis] 01/03: CoverageSubset clip the area to read to the area of
interest specified in the query.
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 bec5a17479b82e8ad3b6164d965b3896d42dde27
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Sun Oct 27 16:52:54 2019 +0100
CoverageSubset clip the area to read to the area of interest specified in the query.
---
.../sis/internal/storage/query/CoverageQuery.java | 62 +++++++------------
.../sis/internal/storage/query/CoverageSubset.java | 71 +++++++++++++++++-----
2 files changed, 77 insertions(+), 56 deletions(-)
diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/CoverageQuery.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/CoverageQuery.java
index b88a673..08724c0 100644
--- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/CoverageQuery.java
+++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/CoverageQuery.java
@@ -27,6 +27,7 @@ import org.apache.sis.measure.AngleFormat;
import org.apache.sis.coverage.grid.GridGeometry;
import org.apache.sis.storage.GridCoverageResource;
import org.apache.sis.storage.Query;
+import org.apache.sis.storage.UnsupportedQueryException;
import org.apache.sis.util.ArgumentChecks;
@@ -86,16 +87,26 @@ public final class CoverageQuery extends Query implements Cloneable {
/**
* Sets the indices of samples dimensions to read.
+ * A {@code null} value means to read all sample dimensions (no filtering on range).
+ * If non-null, then the {@code range} array shall contain at least one element,
+ * all elements must be positive and no value can be duplicated.
*
- * @param range 0-based indices of sample dimensions to read,
- * or {@code null} or an empty sequence for reading them all.
+ * @param range 0-based indices of sample dimensions to read, or {@code null} for reading them all.
+ * @throws IllegalArgumentException if the given array is empty or contains negative or duplicated values.
*/
- public void setRange(final int... range) {
- this.range = (range != null && range.length != 0) ? range.clone() : null;
+ @SuppressWarnings("AssignmentToCollectionOrArrayFieldFromParameter")
+ public void setRange(int... range) {
+ if (range != null) {
+ range = range.clone();
+ ArgumentChecks.ensureNonEmpty("range", range, 0, Integer.MAX_VALUE, true);
+ // Assign only after we verified that the argument is valid.
+ }
+ this.range = range;
}
/**
- * Returns the indices of samples dimensions to read.
+ * Returns the indices of samples dimensions to read, or {@code null} if there is no filtering on range.
+ * If non-null, the returned array shall never be empty.
*
* @return 0-based indices of sample dimensions to read, or {@code null} for reading them all.
*/
@@ -104,41 +115,6 @@ public final class CoverageQuery extends Query implements Cloneable {
}
/**
- * Converts the given range indices from the indices relative to the sub-coverage
- * to indices relative to the source coverage.
- *
- * @param caller the caller, used for error messages only.
- * @param request the range indices to convert, or {@code null} or empty if none.
- * @return the range of indices relative to the source coverage.
- * @throws IllegalArgumentException if an index is invalid.
- */
- final int[] subrange(final CoverageSubset caller, final int[] request) {
- if (range == null) {
- return request;
- }
- if (request == null || request.length == 0) {
- return range.clone();
- }
- final int[] sub = new int[request.length];
- for (int i=0; i<request.length; i++) {
- final int j = request[i];
- if (j >= 0 && j < range.length) {
- sub[i] = range[j];
- } else {
- throw new IllegalArgumentException(caller.invalidRange(j));
- }
- }
- return sub;
- }
-
- /**
- * Returns the number of range indices, or 0 if no range sub-setting has been specified.
- */
- final int getRangeCount() {
- return (range != null) ? range.length : 0;
- }
-
- /**
* Set a number of additional cells to read on each border of the source grid coverage.
* If non-zero, this property expands the {@linkplain #getDomain() domain} to be read
* by an amount specified in unit of cells of the image to be read. Those cells do not
@@ -171,9 +147,13 @@ public final class CoverageQuery extends Query implements Cloneable {
*
* @param source the coverage resource to filter.
* @return a view over the given coverage resource containing only the given domain and range.
+ * @throws UnsupportedQueryException if this query contains filtering options not yet supported.
*/
- public GridCoverageResource execute(final GridCoverageResource source) {
+ public GridCoverageResource execute(final GridCoverageResource source) throws UnsupportedQueryException {
ArgumentChecks.ensureNonNull("source", source);
+ if (getSourceDomainExpansion() != 0) {
+ throw new UnsupportedQueryException("Source domain expansion not yet supported.");
+ }
return new CoverageSubset(source, clone());
}
diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/CoverageSubset.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/CoverageSubset.java
index 2765820..278ec3f 100644
--- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/CoverageSubset.java
+++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/CoverageSubset.java
@@ -20,6 +20,7 @@ import java.util.List;
import org.apache.sis.coverage.SampleDimension;
import org.apache.sis.coverage.grid.GridCoverage;
import org.apache.sis.coverage.grid.GridGeometry;
+import org.apache.sis.coverage.grid.GridRoundingMode;
import org.apache.sis.storage.GridCoverageResource;
import org.apache.sis.storage.event.StoreListeners;
import org.apache.sis.storage.DataStoreException;
@@ -31,6 +32,11 @@ import org.apache.sis.internal.util.UnmodifiableArrayList;
/**
* The result of {@link CoverageQuery#execute(GridCoverageResource)}.
+ * This implementation merges the domain and range specified by the query with
+ * arguments of {@link GridCoverageResource#read(GridGeometry, int...)} method.
+ *
+ * <p>Current version does not yet support non-zero value for
+ * {@link CoverageQuery#getSourceDomainExpansion()}.</p>
*
* @author Martin Desruisseaux (Geomatys)
* @version 1.1
@@ -39,17 +45,20 @@ import org.apache.sis.internal.util.UnmodifiableArrayList;
*/
final class CoverageSubset extends AbstractGridResource {
/**
- * The coverage resource instances to filter.
+ * The coverage resource instances which provides the data.
*/
private final GridCoverageResource source;
/**
- * The query for filtering the source coverage.
+ * The domain and range to read from the {@linkplain #source} coverage.
*/
private final CoverageQuery query;
/**
* Creates a new coverage resource by filtering the given coverage using the given query.
+ *
+ * @param source the coverage resource instances which provides the data.
+ * @param query the domain and range to read from the {@code source} coverage.
*/
CoverageSubset(final GridCoverageResource source, final CoverageQuery query) {
super(source instanceof StoreListeners ? (StoreListeners) source : null);
@@ -59,6 +68,9 @@ final class CoverageSubset extends AbstractGridResource {
/**
* Returns the valid extent of grid coordinates clipped to the area specified in the query.
+ * It should be the geometry of the coverage that we get when invoking {@link #read read(…)}
+ * with {@code null} arguments, but this is not guaranteed.
+ * The returned grid geometry may be approximate.
*
* @return extent of grid coordinates clipped to the query.
* @throws DataStoreException if an error occurred while reading definitions from the underlying data store,
@@ -66,10 +78,25 @@ final class CoverageSubset extends AbstractGridResource {
*/
@Override
public GridGeometry getGridGeometry() throws DataStoreException {
- GridGeometry domain = source.getGridGeometry();
- final GridGeometry sub = query.getDomain();
- if (sub != null) try {
- domain = domain.derive().subgrid(sub).build();
+ return clip(source.getGridGeometry(), query.getDomain(), GridRoundingMode.NEAREST);
+ }
+
+ /**
+ * Clips the given domain to an area of interest. If any argument is null, the other one is returned.
+ *
+ * @param domain the domain to clip, or {@code null}.
+ * @param areaOfInterest the area of interest, or {@code null}.
+ * @param rounding whether to clip to nearest box or an enclosing box.
+ * @return intersection of the given grid geometry.
+ * @throws DataStoreException if the intersection can not be computed.
+ */
+ private GridGeometry clip(final GridGeometry domain, final GridGeometry areaOfInterest,
+ final GridRoundingMode rounding) throws DataStoreException
+ {
+ if (domain == null) return areaOfInterest;
+ if (areaOfInterest == null) return domain;
+ try {
+ return domain.derive().rounding(rounding).subgrid(areaOfInterest).build();
} catch (IllegalArgumentException | IllegalStateException e) {
final String msg = Resources.forLocale(getLocale()).getString(Resources.Keys.CanNotIntersectDataWithQuery);
final Exception cause = getReferencingCause(e);
@@ -79,7 +106,6 @@ final class CoverageSubset extends AbstractGridResource {
throw new DataStoreException(msg, e);
}
}
- return domain;
}
/**
@@ -92,17 +118,17 @@ final class CoverageSubset extends AbstractGridResource {
@Override
public List<SampleDimension> getSampleDimensions() throws DataStoreException {
final List<SampleDimension> dimensions = source.getSampleDimensions();
- if (query.getRangeCount() == 0) {
+ final int[] range = query.getRange();
+ if (range == null) {
return dimensions;
}
- final int[] range = query.getRange();
final SampleDimension[] subset = new SampleDimension[range.length];
for (int i=0; i<range.length; i++) {
final int j = range[i];
try {
subset[i] = dimensions.get(j);
} catch (IndexOutOfBoundsException e) {
- throw new DataStoreException(invalidRange(j), e);
+ throw new DataStoreException(invalidRange(dimensions.size(), j), e);
}
}
return UnmodifiableArrayList.wrap(subset);
@@ -118,18 +144,33 @@ final class CoverageSubset extends AbstractGridResource {
*/
@Override
public GridCoverage read(GridGeometry domain, int... range) throws DataStoreException {
- if (domain == null) {
- domain = query.getDomain();
+ domain = clip(domain, query.getDomain(), GridRoundingMode.ENCLOSING);
+ final int[] qr = query.getRange();
+ if (range == null) {
+ range = qr;
+ } else if (qr != null) {
+ final int[] sub = new int[range.length];
+ for (int i=0; i<range.length; i++) {
+ final int j = range[i];
+ if (j >= 0 && j < qr.length) {
+ sub[i] = qr[j];
+ } else {
+ throw new IllegalArgumentException(invalidRange(qr.length, j));
+ }
+ }
+ range = sub;
}
- range = query.subrange(this, range);
return source.read(domain, range);
}
/**
* Creates an exception message for an invalid range index.
+ *
+ * @param size number of sample dimensions in source coverage.
+ * @param index the index which is out of bounds.
*/
- final String invalidRange(final int index) {
+ private String invalidRange(final int size, final int index) {
return Resources.forLocale(getLocale()).getString(
- Resources.Keys.InvalidSampleDimensionIndex_2, query.getRangeCount() - 1, index);
+ Resources.Keys.InvalidSampleDimensionIndex_2, size - 1, index);
}
}