This is an automated email from the ASF dual-hosted git repository.
jsorel pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git
The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
new facc539 Coverage : add GridCoverageBuilder helper class
facc539 is described below
commit facc539273a3361afd77050e0d246dcf3c2aba2d
Author: jsorel <[email protected]>
AuthorDate: Tue Mar 17 17:06:42 2020 +0100
Coverage : add GridCoverageBuilder helper class
---
.../sis/coverage/grid/GridCoverageBuilder.java | 280 +++++++++++++++++++++
1 file changed, 280 insertions(+)
diff --git
a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridCoverageBuilder.java
b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridCoverageBuilder.java
new file mode 100644
index 0000000..d1d234b
--- /dev/null
+++
b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridCoverageBuilder.java
@@ -0,0 +1,280 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.coverage.grid;
+
+import java.awt.image.DataBuffer;
+import java.awt.image.DataBufferInt;
+import java.awt.image.RenderedImage;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import org.apache.sis.coverage.SampleDimension;
+import org.apache.sis.internal.coverage.j2d.BufferedGridCoverage;
+import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.util.ArraysExt;
+import org.opengis.geometry.Envelope;
+import org.opengis.metadata.spatial.DimensionNameType;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.datum.PixelInCell;
+import org.opengis.referencing.operation.TransformException;
+
+/**
+ * Helper class for the creation of {@link GridCoverage} instances. This
builder can creates the
+ * parameters to be given to {@linkplain GridCoverage2D} and {@linkplain
BufferedGridCoverage}
+ * from simpler parameters given to this builder.
+ *
+ * @author Johann Sorel (Geomatys)
+ */
+public class GridCoverageBuilder {
+
+ private List<SampleDimension> ranges;
+ private RenderedImage image;
+ private DataBuffer buffer;
+ private int bufferWidth = -1;
+ private int bufferHeight = -1;
+ private int bufferNbSample = -1;
+ private GridGeometry grid;
+
+ /**
+ * Sets coverage data rendered image.
+ *
+ * @param image The rendered image to be wrapped by {@code
GridCoverage2D}, not {@code null}.
+ */
+ public void setValues(RenderedImage image) {
+ ArgumentChecks.ensureNonNull("image", image);
+ this.image = image;
+ this.buffer = null;
+ this.bufferWidth = -1;
+ this.bufferHeight = -1;
+ this.bufferNbSample = -1;
+ }
+
+ /**
+ * Creates a coverage from the given matrix.
+ * This method copies the values from the given matrix to a new DataBuffer.
+ * <p>
+ * The coverage height will be the length of the {@code matrix} argument.
+ * The coverage width will be the length of the first row, all rows are
expected
+ * to have the same length.
+ *
+ * @param matrix The matrix data in a {@code [row][column]} layout.
+ * @throws ArithmeticException if the buffer size exceeds the {@code int}
capacity.
+ */
+ public void setValues(int[][] matrix) throws ArithmeticException {
+ final int height = matrix.length;
+ final int width = matrix[0].length;
+ final int[] datas = new int[StrictMath.toIntExact( ((long) height) *
width)];
+ for (int i = 0, offset=0; i < matrix.length; i++,offset+=width) {
+ System.arraycopy(matrix[i], 0, datas, offset, width);
+ }
+ final DataBuffer buffer = new DataBufferInt(datas, datas.length);
+ setValues(buffer, width, height);
+ }
+
+ /**
+ * Creates a coverage from the given matrix.
+ * This method copies the values from the given matrix to a new DataBuffer.
+ * <p>
+ * The coverage height will be the length of the {@code matrix} argument.
+ * The coverage width will be the length of the first row, all rows are
expected
+ * to have the same length.
+ *
+ * @param matrix The matrix data in a {@code [row][column]} layout.
+ * @throws ArithmeticException if the buffer size exceeds the {@code int}
capacity.
+ */
+ public void setValues(float[][] matrix) throws ArithmeticException {
+ final int height = matrix.length;
+ final int width = matrix[0].length;
+ final int[] datas = new int[StrictMath.toIntExact( ((long) height) *
width)];
+ for (int i = 0, offset=0; i < matrix.length; i++,offset+=width) {
+ System.arraycopy(matrix[i], 0, datas, offset, width);
+ }
+ final DataBuffer buffer = new DataBufferInt(datas, datas.length);
+ setValues(buffer, width, height);
+ }
+
+ /**
+ * Creates a coverage from the given matrix.
+ * This method copies the values from the given matrix to a new DataBuffer.
+ * <p>
+ * The coverage height will be the length of the {@code matrix} argument.
+ * The coverage width will be the length of the first row, all rows are
expected
+ * to have the same length.
+ *
+ * @param matrix The matrix data in a {@code [row][column]} layout.
+ * @throws ArithmeticException if the buffer size exceeds the {@code int}
capacity.
+ */
+ public void setValues(double[][] matrix) throws ArithmeticException {
+ final int height = matrix.length;
+ final int width = matrix[0].length;
+ final int[] datas = new int[StrictMath.toIntExact( ((long) height) *
width)];
+ for (int i = 0, offset=0; i < matrix.length; i++,offset+=width) {
+ System.arraycopy(matrix[i], 0, datas, offset, width);
+ }
+ final DataBuffer buffer = new DataBufferInt(datas, datas.length);
+ setValues(buffer, width, height);
+ }
+
+ /**
+ * Creates a coverage from the given buffer.
+ * This method uses the given buffer unmodified to create the coverage.
+ *
+ * @param data the coverage datas, not {@code null}.
+ */
+ public void setValues(DataBuffer data) {
+ ArgumentChecks.ensureNonNull("data", data);
+ this.buffer = data;
+ this.bufferWidth = -1;
+ this.bufferHeight = -1;
+ this.bufferNbSample = -1;
+ }
+
+ private void setValues(DataBuffer data, int width, int height) {
+ this.buffer = data;
+ this.bufferWidth = width;
+ this.bufferHeight = height;
+ this.bufferNbSample = 1;
+ }
+
+ /**
+ * Sets the grid geometry to the given envelope.
+ * This method creates a new {@link GridGeometry}
+ * then invokes {@link #setDomain(GridGeometry)}.
+ *
+ * @param envelope The new grid geometry envelope, or {@code null}.
+ */
+ public void setDomain(Envelope envelope) {
+ setDomain(envelope == null ? null : new GridGeometry(null, envelope));
+ }
+
+ /**
+ * Sets the grid geometry to the given value.
+ *
+ * @param grid The new grid geometry, or {@code null}.
+ */
+ public void setDomain(GridGeometry grid) {
+ this.grid = grid;
+ }
+
+ /**
+ * Sets all sample dimensions.
+ *
+ * @param range The new sample dimensions, or {@code null}.
+ */
+ public void setRanges(final SampleDimension... range) {
+ this.ranges = (range == null) ? null : new
ArrayList<>(Arrays.asList(range));
+ }
+
+ /**
+ * Sets all sample dimensions.
+ *
+ * @param range The new sample dimensions, or {@code null}.
+ */
+ public void setRanges(Collection<? extends SampleDimension> range) {
+ this.ranges = (range == null) ? null : new ArrayList<>(range);
+ }
+
+ /**
+ * Creates the grid coverage.
+ * Current implementation may create a {@link BufferedGridCoverage} or
{@link GridCoverage2D},
+ * but future implementations may instantiate different other coverage
types.
+ *
+ * @return created coverage
+ * @throws IllegalGridGeometryException if the {@code domain} does not met
the above-documented conditions.
+ * @throws IllegalArgumentException if the image number of bands is not
the same than the number of sample dimensions.
+ */
+ public GridCoverage build() {
+
+ if (image != null) {
+ return new GridCoverage2D(grid, ranges, image);
+ } else if (buffer != null) {
+
+ GridGeometry grid = this.grid;
+ List<SampleDimension> ranges = this.ranges;
+
+ //verify and enrich grid geometry
+ if (bufferWidth != -1) {
+ if (grid.isDefined(GridGeometry.EXTENT)) {
+ GridExtent extent = grid.getExtent();
+ if (extent.getDimension() != 2) {
+ throw new IllegalGridGeometryException("Grid dimension
differ from buffer size, expected 2 found " + extent.getDimension());
+ } else if (extent.getSize(0) != bufferWidth) {
+ throw new IllegalGridGeometryException("Grid width
differ from buffer width, expected " + bufferWidth + " found " +
extent.getSize(0));
+ } else if (extent.getSize(1) != bufferHeight) {
+ throw new IllegalGridGeometryException("Grid height
differ from buffer height, expected " + bufferHeight + " found " +
extent.getSize(1));
+ }
+ } else {
+ grid = addExtentIfAbsent(grid, bufferWidth, bufferHeight);
+ }
+ }
+ //verify sample dimensions
+ if (bufferNbSample != -1) {
+ if (ranges != null && ranges.size() != bufferNbSample) {
+ throw new IllegalArgumentException("Sample dimension list
differ from matrix, expected " + bufferNbSample + " found " + ranges.size());
+ }
+ if (ranges == null) {
+ //create default dimensions
+ ranges = new ArrayList<>(bufferNbSample);
+ for (int i = 0; i < bufferNbSample; i++) {
+ ranges.add(new
SampleDimension.Builder().setName(i).build());
+ }
+ }
+ }
+
+ return new BufferedGridCoverage(grid, ranges, buffer);
+ } else {
+ throw new IllegalArgumentException("Image, buffer or matrix must
be set before building coverage.");
+ }
+ }
+
+ /**
+ * If the given domain does not have a {@link GridExtent}, creates a new
grid geometry
+ * with an extent of given size.
+ */
+ private static GridGeometry addExtentIfAbsent(GridGeometry domain, int
width, int height) {
+ if (domain == null) {
+ GridExtent extent = new GridExtent(width, height);
+ domain = new GridGeometry(extent, PixelInCell.CELL_CENTER, null,
null);
+ } else if (!domain.isDefined(GridGeometry.EXTENT)) {
+ final int dimension = domain.getDimension();
+ if (dimension >= 2) {
+ CoordinateReferenceSystem crs = null;
+ if (domain.isDefined(GridGeometry.CRS)) {
+ crs = domain.getCoordinateReferenceSystem();
+ }
+ final long[] low = new long[dimension];
+ final long[] high = new long[dimension];
+ high[0] = width - 1; // Inclusive.
+ high[1] = height - 1;
+ DimensionNameType[] axisTypes = GridExtent.typeFromAxes(crs,
dimension);
+ if (axisTypes == null) {
+ axisTypes = new DimensionNameType[dimension];
+ }
+ if (!ArraysExt.contains(axisTypes, DimensionNameType.COLUMN))
axisTypes[0] = DimensionNameType.COLUMN;
+ if (!ArraysExt.contains(axisTypes, DimensionNameType.ROW))
axisTypes[1] = DimensionNameType.ROW;
+ final GridExtent extent = new GridExtent(axisTypes, low, high,
true);
+ try {
+ domain = new GridGeometry(domain, extent, null);
+ } catch (TransformException e) {
+ throw new IllegalGridGeometryException(e);
// Should never happen.
+ }
+ }
+ }
+ return domain;
+ }
+}