/*
* Geotoolkit.org - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2005-2012, Open Source Geospatial Foundation (OSGeo)
* (C) 2009-2012, 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.coverage.grid;
import java.util.Map;
import java.util.Arrays;
import java.util.Objects;
import java.awt.Color;
import java.awt.RenderingHints;
import java.awt.image.ColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.awt.image.renderable.ParameterBlock;
import java.awt.geom.AffineTransform;
import javax.media.jai.JAI;
import javax.media.jai.PlanarImage;
import javax.media.jai.ImageFunction;
import javax.media.jai.RasterFactory;
import javax.media.jai.util.CaselessStringKey;
import javax.measure.Unit;
import org.opengis.coverage.SampleDimensionType;
import org.opengis.coverage.grid.GridCoverage;
import org.opengis.coverage.grid.GridEnvelope;
import org.opengis.referencing.cs.AxisDirection;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.geometry.Envelope;
import org.geotoolkit.factory.Hints;
import org.geotoolkit.factory.Factory;
import org.geotoolkit.internal.FactoryUtilities;
import org.apache.sis.geometry.GeneralEnvelope;
import org.geotoolkit.coverage.GridSampleDimension;
import org.geotoolkit.resources.Errors;
import org.apache.sis.referencing.CommonCRS;
import org.apache.sis.referencing.crs.AbstractCRS;
import org.apache.sis.referencing.cs.AxesConvention;
/**
* A factory for {@linkplain GridCoverage2D grid coverage} objects. This factory expects various
* combinations of the following informations:
* <p>
* <ul>
* <li>A name as a {@linkplain CharSequence character sequence}.</li>
*
* <li>A {@linkplain WritableRaster raster}, <strong>or</strong> an {@linkplain RenderedImage
* image}, <strong>or</strong> an {@linkplain ImageFunction image function}, <strong>or</strong>
* a matrix of kind {@code float[][]}.</li>
*
* <li>A ({@linkplain CoordinateReferenceSystem coordinate reference system} -
* {@linkplain MathTransform transform}) pair, <strong>or</strong> an {@linkplain Envelope
* envelope}, <strong>or</strong> a {@linkplain GridGeometry2D grid geometry}. The envelope
* is easier to use, while the transform provides more control.</li>
*
* <li>Information about each {@linkplain GridSampleDimension sample dimensions} (often
* called <cite>bands</cite> in the particular case of images), <strong>or</strong> minimal
* and maximal expected values for each bands.</li>
*
* <li>Optional properties as a {@linkplain Map map} of <cite>key</cite>-<cite>value</cite> pairs.
* "Properties" in <cite>Java Advanced Imaging</cite> are called "Metadata" by OpenGIS.
* Keys are {@link String} objects ({@link CaselessStringKey} are accepted as well), while
* values may be any {@link Object}.</li>
* </ul>
* <p>
* The {@linkplain CoordinateReferenceSystem coordinate reference system} is inferred from the
* supplied {@linkplain Envelope envelope} or {@linkplain GridGeometry2D grid geometry} parameters.
* If those parameters do not have CRS information, then this factory fallback on a {@linkplain
* #getDefaultCRS default CRS}.
* <p>
* Every {@code create} methods will ultimately delegate their work to a master
* {@link #create(CharSequence, RenderedImage, GridGeometry2D, GridSampleDimension[],
* GridCoverage[], Map) create} variant. Developers can override this method if they
* want to intercept the creation of all {@link GridCoverage2D} objects in this factory.
*
* @author Martin Desruisseaux (IRD, Geomatys)
* @version 3.20
*
* @since 2.1
* @module
*
* @deprecated Replaced by {@link GridCoverageBuilder}.
*/
@Deprecated
public class GridCoverageFactory extends Factory {
/**
* Whatever we should use {@link GridCoverageBuilder}. As of Geotk 3.20, we use the builder
* for testing purpose on the JDK7 branch but conservatively keep the old algorithms on the
* default branch.
*
* @since 3.20
*/
private static final boolean USE_BUILDER = true;
/**
* The hints to be given to {@link GridCoverageBuilder}, or {@code null} if none.
*/
private final Hints builderHints;
/**
* The hints to be given to coverage constructor.
*
* @todo Put there only the hints we need.
*/
private final Hints userHints = null;
/**
* Creates a default factory. Users should not need to creates instance of this class directly.
* Invoke {@link org.geotoolkit.coverage.CoverageFactoryFinder#getGridCoverageFactory} instead.
*/
public GridCoverageFactory() {
this(EMPTY_HINTS);
}
/**
* Creates a factory using the specified set of hints.
* The factory recognizes the following hints:
* <p>
* <ul>
* <li>{@link Hints#DEFAULT_COORDINATE_REFERENCE_SYSTEM}</li>
* <li>{@link Hints#TILE_ENCODING}</li>
* </ul>
*
* @param userHints An optional set of hints to use for coverage constructions.
*/
public GridCoverageFactory(final Hints userHints) {
CoordinateReferenceSystem defaultCRS = null;
String tileEncoding = null;
if (userHints != null) {
defaultCRS = (CoordinateReferenceSystem) userHints.get(Hints.DEFAULT_COORDINATE_REFERENCE_SYSTEM);
if (Objects.equals(defaultCRS, CommonCRS.WGS84.normalizedGeographic()) ||
Objects.equals(defaultCRS, AbstractCRS.castOrCopy(CommonCRS.WGS84.geographic3D()).forConvention(AxesConvention.RIGHT_HANDED)))
{
// Will be handled in a special way by getDefaultCRS(int)
defaultCRS = null;
}
tileEncoding = (String) userHints.get(Hints.TILE_ENCODING);
if (tileEncoding != null) {
tileEncoding = tileEncoding.trim();
if (tileEncoding.isEmpty()) {
tileEncoding = null;
}
}
}
hints.put(Hints.DEFAULT_COORDINATE_REFERENCE_SYSTEM, defaultCRS);
hints.put(Hints.TILE_ENCODING, tileEncoding);
final Hints copy = new Hints(EMPTY_HINTS);
FactoryUtilities.addValidEntries(hints, copy, true);
builderHints = copy.isEmpty() ? null : copy;
}
/**
* Returns the default coordinate reference system to use when no CRS were explicitly
* specified by the user. If a {@link Hints#DEFAULT_COORDINATE_REFERENCE_SYSTEM
* DEFAULT_COORDINATE_REFERENCE_SYSTEM} hint were provided at factory construction
* time, then the specified CRS is returned. Otherwise, the default implementation
* returns {@link DefaultGeographicCRS#WGS84} or its 3D variant. Subclasses should
* override this method if they want to use different defaults.
*
* @param dimension The number of dimension expected in the CRS to be returned.
* @return The new grid coverage.
*
* @since 2.2
*/
protected CoordinateReferenceSystem getDefaultCRS(final int dimension) {
final CoordinateReferenceSystem candidate = (CoordinateReferenceSystem)
hints.get(Hints.DEFAULT_COORDINATE_REFERENCE_SYSTEM);
if (candidate != null) {
return candidate;
}
switch (dimension) {
case 2: return CommonCRS.WGS84.normalizedGeographic();
case 3: return AbstractCRS.castOrCopy(CommonCRS.WGS84.geographic3D()).forConvention(AxesConvention.RIGHT_HANDED);
default: throw new IllegalArgumentException(Errors.format(
Errors.Keys.IllegalArgument_2, "dimension", dimension));
}
}
/**
* Constructs a grid coverage from an {@linkplain ImageFunction image function}.
*
* @param name
* The grid coverage name, or {@code null} if none.
* @param function
* The image function.
* @param gridGeometry
* The grid geometry. The {@linkplain GridGeometry2D#getExtent() grid extent}
* must contains the expected image size (width and height).
* @param bands
* Sample dimensions for each image band, or {@code null} for default sample dimensions.
* @param properties
* The set of properties for this coverage, or {@code null} if there is none.
* @return The new grid coverage.
*
* @since 2.2
*/
public GridCoverage2D create(final CharSequence name,
final ImageFunction function,
final GridGeometry2D gridGeometry,
final GridSampleDimension[] bands,
final Map<?,?> properties)
{
final MathTransform transform = gridGeometry.getGridToCRS2D();
if (!(transform instanceof AffineTransform)) {
throw new IllegalArgumentException(Errors.format(Errors.Keys.NotAnAffineTransform));
}
final AffineTransform at = (AffineTransform) transform;
if (at.getShearX()!=0 || at.getShearY()!=0) {
// TODO: We may support that in a future version.
// 1) Create a copy with shear[X/Y] set to 0. Use the copy.
// 2) Compute the residu with createInverse() and concatenate().
// 3) Apply the residu with JAI.create("Affine").
throw new IllegalArgumentException("Shear and rotation not supported");
}
final double xScale = at.getScaleX();
final double yScale = at.getScaleY();
final double xTrans = -at.getTranslateX() / xScale;
final double yTrans = -at.getTranslateY() / yScale;
final GridEnvelope extent = gridGeometry.getExtent();
final ParameterBlock param = new ParameterBlock()
.add(function)
.add(extent.getSpan(0)) // width
.add(extent.getSpan(1)) // height
.add((float) xScale)
.add((float) yScale)
.add((float) xTrans)
.add((float) yTrans);
final PlanarImage image = JAI.create("ImageFunction", param);
return create(name, image, gridGeometry, bands, null, properties);
}
/**
* Constructs a grid coverage from the specified matrix and {@linkplain Envelope envelope}.
* A default color palette is built from the minimal and maximal values found in the matrix.
*
* @param name
* The grid coverage name, or {@code null} if none.
* @param matrix
* The matrix data in a {@code [row][column]} layout.
* {@linkplain Float#NaN NaN} values are mapped to a transparent color.
* @param envelope
* The envelope.
* @return The new grid coverage.
*
* @since 2.2
*/
public GridCoverage2D create(final CharSequence name,
final float[][] matrix,
final Envelope envelope)
{
if (USE_BUILDER) {
final GridCoverageBuilder builder = new GridCoverageBuilder(builderHints);
builder.setName(name);
builder.setEnvelope(envelope);
builder.setRenderedImage(matrix);
return builder.getGridCoverage2D();
}
int width = 0;
int height = matrix.length;
for (int j=0; j<height; j++) {
final float[] row = matrix[j];
if (row != null) {
if (row.length > width) {
width = row.length;
}
}
}
final WritableRaster raster;
// Need to use JAI raster factory, since WritableRaster
// does not supports TYPE_FLOAT as of J2SE 1.5.0_06.
raster = RasterFactory.createBandedRaster(DataBuffer.TYPE_FLOAT, width, height, 1, null);
for (int j=0; j<height; j++) {
int i = 0;
final float[] row = matrix[j];
if (row != null) {
for (; i<row.length; i++) {
raster.setSample(i, j, 0, row[i]);
}
}
for (; i<width; i++) {
raster.setSample(i, j, 0, Float.NaN);
}
}
return create(name, raster, envelope);
}
/**
* Constructs a grid coverage from the specified {@linkplain WritableRaster raster} and
* {@linkplain Envelope envelope}. A default color palette is built from the minimal and
* maximal values found in the raster.
*
* @param name
* The grid coverage name, or {@code null} if none.
* @param raster
* The data (may be floating point numbers). {@linkplain Float#NaN NaN}
* values are mapped to a transparent color.
* @param envelope
* The envelope.
* @return The new grid coverage.
*/
public GridCoverage2D create(final CharSequence name,
final WritableRaster raster,
final Envelope envelope)
{
return create(name, raster, envelope, null, null, null, null, null);
}
/**
* Constructs a grid coverage from the specified {@linkplain WritableRaster raster} and
* {@linkplain Envelope envelope}.
*
* See the {@linkplain #create(CharSequence, RenderedImage, Envelope, GridSampleDimension[],
* GridCoverage[], Map) rendered image variant} for a note on heuristic rules applied by this
* method.
*
* @param name
* The grid coverage name, or {@code null} if none.
* @param raster
* The data (may be floating point numbers).
* {@linkplain Float#NaN NaN} values are mapped to a transparent color.
* @param envelope
* The grid coverage coordinates and its CRS. This envelope must have at least two
* dimensions. The two first dimensions describe the image location along <var>x</var>
* and <var>y</var> axis. The other dimensions are optional and may be used to locate
* the image on a vertical axis or on the time axis.
* @param minValues
* The minimal value for each band in the raster,
* or {@code null} for computing it automatically.
* @param maxValues
* The maximal value for each band in the raster,
* or {@code null} for computing it automatically.
* @param units
* The units of sample values, or {@code null} if unknown.
* @param colors
* The colors to use for values from {@code minValues} to {@code maxValues} for each
* bands, or {@code null} for a default color palette. If non-null, each arrays
* {@code colors[b]} may have any length; colors will be interpolated as needed.
* @param hints
* An optional set of rendering hints, or {@code null} if none. Those hints will not
* affect the grid coverage to be created. However, they may affect the grid coverage
* to be returned by <code>{@link GridCoverage2D#view view}(View.RENDERED)</code>.
* The optional {@link Hints#SAMPLE_DIMENSION_TYPE SAMPLE_DIMENSION_TYPE} hint
* specifies the {@link SampleDimensionType} to be used at rendering time, which can
* be one of {@link SampleDimensionType#UNSIGNED_8BITS UNSIGNED_8BITS} or
* {@link SampleDimensionType#UNSIGNED_16BITS UNSIGNED_16BITS}.
* @return The new grid coverage.
*
* @since 2.2
*/
public GridCoverage2D create(final CharSequence name,
final WritableRaster raster,
final Envelope envelope,
final double[] minValues,
final double[] maxValues,
final Unit<?> units,
final Color[][] colors,
final RenderingHints hints)
{
if (USE_BUILDER) {
final Hints merge = new Hints(builderHints);
if (hints != null) merge.putAll(hints);
final GridCoverageBuilder builder = new GridCoverageBuilder(merge);
builder.setName(name);
builder.setEnvelope(envelope);
builder.setSampleDimensions(minValues, maxValues, units, colors);
builder.setRenderedImage(raster);
return builder.getGridCoverage2D();
}
final int numBands = raster.getNumBands();
final Unit<?>[] unitsArray = new Unit<?>[numBands]; Arrays.fill(unitsArray, units);
final CharSequence[] names = new CharSequence[numBands]; Arrays.fill(names, name);
final GridSampleDimension[] bands =
RenderedSampleDimension.create(names, raster, minValues, maxValues, unitsArray, colors, hints);
final ColorModel model = bands[0].getColorModel(0, bands.length, raster.getDataBuffer().getDataType());
final RenderedImage image = new BufferedImage(model, raster, false, null);
return create(name, image, envelope, bands, null, null);
}
/**
* Constructs a grid coverage from the specified {@linkplain WritableRaster raster} and
* "{@linkplain GridGeometry2D#getGridToCRS grid to CRS}" transform.
*
* @param name
* The grid coverage name, or {@code null} if none.
* @param raster
* The data (may be floating point numbers).
* {@linkplain Float#NaN NaN} values are mapped to a transparent color.
* @param crs
* The coordinate reference system. This specifies the CRS used when
* accessing a grid coverage with the {@code evaluate} methods.
* @param gridToCRS
* The math transform from grid to coordinate reference system.
* @param minValues
* The minimal value for each band in the raster,
* or {@code null} for computing it automatically.
* @param maxValues
* The maximal value for each band in the raster,
* or {@code null} for computing it automatically.
* @param units
* The units of sample values, or {@code null} if unknown.
* @param colors
* The colors to use for values from {@code minValues} to {@code maxValues} for each
* bands, or {@code null} for a default color palette. If non-null, each arrays
* {@code colors[b]} may have any length; colors will be interpolated as needed.
* @param hints
* An optional set of rendering hints, or {@code null} if none. Those hints will not
* affect the grid coverage to be created. However, they may affect the grid coverage
* to be returned by <code>{@link GridCoverage2D#view view}(View.RENDERED)</code>.
* The optional {@link Hints#SAMPLE_DIMENSION_TYPE SAMPLE_DIMENSION_TYPE} hint
* specifies the {@link SampleDimensionType} to be used at rendering time, which can
* be one of {@link SampleDimensionType#UNSIGNED_8BITS UNSIGNED_8BITS} or
* {@link SampleDimensionType#UNSIGNED_16BITS UNSIGNED_16BITS}.
* @return The new grid coverage.
*/
public GridCoverage2D create(final CharSequence name,
final WritableRaster raster,
final CoordinateReferenceSystem crs,
final MathTransform gridToCRS,
final double[] minValues,
final double[] maxValues,
final Unit<?> units,
final Color[][] colors,
final RenderingHints hints)
{
if (USE_BUILDER) {
final Hints merge = new Hints(builderHints);
if (hints != null) merge.putAll(hints);
final GridCoverageBuilder builder = new GridCoverageBuilder(merge);
builder.setName(name);
builder.setCoordinateReferenceSystem(crs);
builder.setGridToCRS(gridToCRS);
builder.setSampleDimensions(minValues, maxValues, units, colors);
builder.setRenderedImage(raster);
return builder.getGridCoverage2D();
}
final int numBands = raster.getNumBands();
final Unit<?>[] unitsArray = new Unit<?>[numBands]; Arrays.fill(unitsArray, units);
final CharSequence[] names = new CharSequence[numBands]; Arrays.fill(names, name);
final GridSampleDimension[] bands =
RenderedSampleDimension.create(names, raster, minValues, maxValues, unitsArray, colors, hints);
final ColorModel model = bands[0].getColorModel(0, bands.length, raster.getDataBuffer().getDataType());
final RenderedImage image = new BufferedImage(model, raster, false, null);
return create(name, image, crs, gridToCRS, bands, null, null);
}
/**
* Creates default bands for the given raster.
*
* @param name The sample dimension name, or {@code null} if none.
* @param raster The raster for which sample dimensions are being built.
* @return The sample dimensions.
*/
private static GridSampleDimension[] createDefaultBands(final CharSequence name, final Raster raster) {
final GridSampleDimension[] bands = new GridSampleDimension[raster.getNumBands()];
RenderedSampleDimension.create(name, null, raster, raster.getSampleModel(), null, bands);
return bands;
}
/**
* Constructs a grid coverage from the specified {@linkplain WritableRaster raster}
* and {@linkplain Envelope envelope}. This convenience constructor performs the same
* assumptions on axis order than the {@linkplain #create(CharSequence, RenderedImage,
* Envelope, GridSampleDimension[], GridCoverage[], Map) rendered image variant}.
* <p>
* The {@linkplain CoordinateReferenceSystem coordinate reference system} is inferred from the
* supplied envelope. The envelope must have at least two dimensions. The two first dimensions
* describe the image location along <var>x</var> and <var>y</var> axis. The other dimensions
* are optional and may be used to locate the image on a vertical axis or on the time axis.
*
* @param name
* The grid coverage name, or {@code null} if none.
* @param raster
* The raster.
* @param envelope
* The grid coverage coordinates.
* @param bands
* Sample dimensions for each image band, or {@code null} for default sample dimensions.
* If non-null, then this array length must matches the number of bands in {@code image}.
* @return The new grid coverage.
*
* @since 2.2
*/
public GridCoverage2D create(final CharSequence name,
final WritableRaster raster,
final Envelope envelope,
GridSampleDimension... bands)
{
if (USE_BUILDER) {
final GridCoverageBuilder builder = new GridCoverageBuilder(builderHints);
builder.setName(name);
builder.setEnvelope(envelope);
builder.setSampleDimensions(bands);
builder.setRenderedImage(raster);
return builder.getGridCoverage2D();
}
if (bands == null || bands.length == 0) {
bands = createDefaultBands(name, raster);
}
final ColorModel model = bands[0].getColorModel(0, bands.length, raster.getDataBuffer().getDataType());
final RenderedImage image = new BufferedImage(model, raster, false, null);
return create(name, image, envelope, bands, null, null);
}
/**
* Constructs a grid coverage from the specified {@linkplain WritableRaster raster} and
* "{@linkplain GridGeometry2D#getGridToCRS grid to CRS}" transform.
*
* @param name
* The grid coverage name, or {@code null} if none.
* @param raster
* The raster.
* @param crs
* The coordinate reference system. This specifies the CRS used when accessing a grid
* coverage with the {@code evaluate} methods. The number of dimensions must matches
* the number of target dimensions of {@code gridToCRS}.
* @param gridToCRS
* The math transform from grid to coordinate reference system.
* @param bands
* Sample dimensions for each image band, or {@code null} for default sample dimensions.
* If non-null, then this array length must matches the number of bands in {@code image}.
* @return The new grid coverage.
*
* @since 2.2
*/
public GridCoverage2D create(final CharSequence name,
final WritableRaster raster,
final CoordinateReferenceSystem crs,
final MathTransform gridToCRS,
GridSampleDimension... bands)
{
if (USE_BUILDER) {
final GridCoverageBuilder builder = new GridCoverageBuilder(builderHints);
builder.setName(name);
builder.setCoordinateReferenceSystem(crs);
builder.setGridToCRS(gridToCRS);
builder.setSampleDimensions(bands);
builder.setRenderedImage(raster);
return builder.getGridCoverage2D();
}
if (bands == null || bands.length == 0) {
bands = createDefaultBands(name, raster);
}
final ColorModel model = bands[0].getColorModel(0, bands.length, raster.getDataBuffer().getDataType());
final RenderedImage image = new BufferedImage(model, raster, false, null);
return create(name, image, crs, gridToCRS, bands, null, null);
}
/**
* Constructs a grid coverage from the specified {@linkplain RenderedImage image} and
* {@linkplain Envelope envelope}. A default set of {@linkplain GridSampleDimension sample
* dimensions} is used. The {@linkplain CoordinateReferenceSystem coordinate reference system}
* is inferred from the supplied envelope.
* <p>
* The envelope must have at least two dimensions. The two first dimensions describe the image
* location along <var>x</var> and <var>y</var> axis. The other dimensions are optional and may
* be used to locate the image on a vertical axis or on the time axis.
*
* @param name The grid coverage name, or {@code null} if none.
* @param image The image.
* @param envelope The grid coverage coordinates.
* @return The new grid coverage.
*
* @since 2.2
*/
public GridCoverage2D create(final CharSequence name,
final RenderedImage image,
final Envelope envelope)
{
if (USE_BUILDER) {
final GridCoverageBuilder builder = new GridCoverageBuilder(builderHints);
builder.setName(name);
builder.setEnvelope(envelope);
builder.setRenderedImage(image);
return builder.getGridCoverage2D();
}
return create(name, image, envelope, null, null, null);
}
/**
* Constructs a grid coverage from the specified {@linkplain RenderedImage image} and
* {@linkplain Envelope envelope}. An {@linkplain AffineTransform affine transform} will
* be computed automatically from the specified envelope using heuristic rules described below.
* <p>
* This convenience constructor assumes that axis order in the supplied image matches exactly
* axis order in the supplied envelope. In other words, in the usual case where axis order in
* the image is (<var>column</var>, <var>row</var>), then the envelope should probably have a
* (<var>longitude</var>, <var>latitude</var>) or (<var>easting</var>, <var>northing</var>)
* axis order.
* <p>
* An exception to the above rule applies for CRS using exactly the following axis order:
* ({@link AxisDirection#NORTH NORTH}|{@link AxisDirection#SOUTH SOUTH},
* {@link AxisDirection#EAST EAST}|{@link AxisDirection#WEST WEST}).
* An example of such CRS is {@code EPSG:4326}. This convenience constructor will
* interchange automatically the (<var>y</var>,<var>x</var>) axis for such CRS.
* <p>
* If more control on axis order and direction reversal is wanted, use the {@linkplain
* #create(CharSequence, RenderedImage, CoordinateReferenceSystem, MathTransform,
* GridSampleDimension[], GridCoverage[], Map) constructor variant expecting an explicit
* transform}.
*
* @param name
* The grid coverage name, or {@code null} if none.
* @param image
* The image.
* @param envelope
* The grid coverage coordinates. This envelope must have at least two dimensions.
* The two first dimensions describe the image location along <var>x</var> and
* <var>y</var> axis. The other dimensions are optional and may be used to locate
* the image on a vertical axis or on the time axis.
* @param bands
* Sample dimensions for each image band, or {@code null} for default sample dimensions.
* If non-null, then this array length must matches the number of bands in {@code image}.
* @param sources
* The sources for this grid coverage, or {@code null} if none.
* @param properties
* The set of properties for this coverage, or {@code null} if there is none.
* @return The new grid coverage.
*
* @since 2.2
*/
public GridCoverage2D create(final CharSequence name,
final RenderedImage image,
Envelope envelope,
final GridSampleDimension[] bands,
final GridCoverage[] sources,
final Map<?,?> properties)
{
if (USE_BUILDER) {
final GridCoverageBuilder builder = new GridCoverageBuilder(builderHints);
builder.setName(name);
builder.setEnvelope(envelope);
builder.setRenderedImage(image); // It is safer to define after the grid geometry.
builder.setSampleDimensions(bands);
builder.setSources(sources);
builder.setProperties(properties);
return builder.getGridCoverage2D();
}
/*
* Makes sure that the specified envelope has a CRS.
* If no CRS were specified, a default one is used.
*/
if (envelope.getCoordinateReferenceSystem() == null) {
final GeneralEnvelope e = new GeneralEnvelope(envelope);
e.setCoordinateReferenceSystem(getDefaultCRS(e.getDimension()));
envelope = e;
}
final GridGeometry2D gm = new GridGeometry2D(
new GeneralGridEnvelope(image, envelope.getDimension()), envelope);
return create(name, image, gm, bands, sources, properties);
}
/**
* Constructs a grid coverage from the specified {@linkplain RenderedImage image} and
* "{@linkplain GridGeometry2D#getGridToCRS grid to CRS}" transform.
*
* @param name
* The grid coverage name, or {@code null} if none.
* @param image
* The image.
* @param crs
* The coordinate reference system. This specifies the CRS used when accessing a grid
* coverage with the {@code evaluate} methods. The number of dimensions must matches
* the number of target dimensions of {@code gridToCRS}.
* @param gridToCRS
* The math transform from grid to coordinate reference system.
* @param bands
* Sample dimension for each image band, or {@code null} for default sample dimensions.
* If non-null, then this array length must matches the number of bands in the {@code image}.
* @param sources
* The sources for this grid coverage, or {@code null} if none.
* @param properties
* The set of properties for this coverage, or {@code null} if there is none.
* @return The new grid coverage.
*/
public GridCoverage2D create(final CharSequence name,
final RenderedImage image,
final CoordinateReferenceSystem crs,
final MathTransform gridToCRS,
final GridSampleDimension[] bands,
final GridCoverage[] sources,
final Map<?,?> properties)
{
if (USE_BUILDER) {
final GridCoverageBuilder builder = new GridCoverageBuilder(builderHints);
builder.setName(name);
builder.setCoordinateReferenceSystem(crs);
builder.setGridToCRS(gridToCRS);
builder.setRenderedImage(image); // It is safer to define after the grid geometry.
builder.setSampleDimensions(bands);
builder.setSources(sources);
builder.setProperties(properties);
return builder.getGridCoverage2D();
}
final GridGeometry2D gm = new GridGeometry2D(new GeneralGridEnvelope(image,
crs.getCoordinateSystem().getDimension()), gridToCRS, crs);
return create(name, image, gm, bands, sources, properties);
}
/**
* Constructs a grid coverage from the specified {@linkplain RenderedImage image} and
* {@linkplain GridGeometry2D grid geometry}. The {@linkplain Envelope envelope}
* (including the {@linkplain CoordinateReferenceSystem coordinate reference system})
* is inferred from the grid geometry.
* <p>
* This is the most general constructor, the one that gives the maximum control
* on the grid coverage to be created. Every {@code create} methods will ultimately
* delegate their work this master method. Developers can override this method if they
* want to intercept the creation of all {@link GridCoverage2D} objects in this factory.
*
* @param name
* The grid coverage name, or {@code null} if none.
* @param image
* The image.
* @param gridGeometry
* The grid geometry (must contains an {@linkplain GridGeometry2D#getEnvelope envelope}
* with its {@linkplain GridGeometry2D#getCoordinateReferenceSystem coordinate reference
* system} and a "{@linkplain GridGeometry2D#getGridToCRS grid to CRS}" transform).
* @param bands
* Sample dimensions for each image band, or {@code null} for default sample dimensions.
* If non-null, then this array length must matches the number of bands in {@code image}.
* @param sources
* The sources for this grid coverage, or {@code null} if none.
* @param properties
* The set of properties for this coverage, or {@code null} none.
* @return The new grid coverage.
*
* @since 2.2
*/
public GridCoverage2D create(final CharSequence name,
final RenderedImage image,
GridGeometry2D gridGeometry,
final GridSampleDimension[] bands,
final GridCoverage[] sources,
final Map<?,?> properties)
{
if (USE_BUILDER) {
final GridCoverageBuilder builder = new GridCoverageBuilder(builderHints);
builder.setName(name);
builder.setGridGeometry(gridGeometry);
builder.setRenderedImage(image); // It is safer to define after the grid geometry.
builder.setSampleDimensions(bands);
builder.setSources(sources);
builder.setProperties(properties);
return builder.getGridCoverage2D();
}
/*
* Makes sure that the specified grid geometry has a CRS.
* If no CRS were specified, a default one is used.
*/
if (!gridGeometry.isDefined(GridGeometry2D.CRS)) {
final int dimension = gridGeometry.getGridToCRS().getTargetDimensions();
gridGeometry = new GridGeometry2D(gridGeometry, getDefaultCRS(dimension));
}
final GridCoverage2D coverage;
coverage = new GridCoverage2D(name, PlanarImage.wrapRenderedImage(image),
gridGeometry, bands, sources, properties, userHints);
coverage.tileEncoding = (String) hints.get(Hints.TILE_ENCODING);
return coverage;
}
}