/*
* Geotoolkit.org - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2001-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.processing;
import java.util.Set;
import java.util.Map;
import java.util.HashMap;
import org.opengis.referencing.IdentifiedObject;
import org.opengis.parameter.ParameterValueGroup;
import org.opengis.parameter.ParameterDescriptor;
import org.opengis.parameter.ParameterDescriptorGroup;
import org.opengis.parameter.ParameterNotFoundException;
import org.opengis.parameter.InvalidParameterValueException;
import org.geotoolkit.factory.Hints;
import org.geotoolkit.coverage.grid.ViewType;
import org.geotoolkit.coverage.grid.GridCoverage2D;
import org.geotoolkit.coverage.grid.GridCoverageFactory;
import org.geotoolkit.coverage.CoverageFactoryFinder;
import org.geotoolkit.metadata.Citations;
import org.geotoolkit.parameter.DefaultParameterDescriptor;
import org.apache.sis.referencing.NamedIdentifier;
import org.apache.sis.util.Classes;
import org.geotoolkit.resources.Errors;
import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
/**
* An operation working on a two-dimensional slice of a coverage. The current implementation
* requires the source to be instances of {@link GridCoverage2D}, but this restriction may be
* relaxed in a future version.
* <p>
* This base class does not really impose any restriction about what the
* {@link #doOperation doOperation} method can do, but it provides convenience methods for
* {@linkplain #extractSources extracting the sources} as {@code GridCoverage2D} objects.
*
* @author Martin Desruisseaux (IRD, Geomatys)
* @version 3.00
*
* @since 1.2
* @module
*
* @deprecated The API of this class will change in a future Geotk release. Do not rely on it.
*/
@Deprecated
public abstract class Operation2D extends AbstractOperation {
/**
* Serial number for inter-operability with different versions.
*/
private static final long serialVersionUID = 574096338873406394L;
/**
* Index of the source {@link GridCoverage2D} to use as a model. The destination grid coverage
* will reuse the same coordinate reference system, envelope and qualitative categories than
* this primary source.
* <p>
* For operations expecting only one source, there is no ambiguity. But for operations
* expecting more than one source, the choice of a primary source is somewhat arbitrary.
* This constant is used merely as a flag for spotting those places in the code.
*
* @since 2.4
*/
protected static final int PRIMARY_SOURCE_INDEX = 0;
/**
* The preferred type of views to be returned by {@link #extractSources},
* in preference order.
*/
private static final ViewType[] PREFERRED_OUTPUTS = {
ViewType.GEOPHYSICS,
ViewType.PACKED,
ViewType.PHOTOGRAPHIC,
ViewType.RENDERED
};
/**
* Convenience constant for the first source {@link GridCoverage2D}. The parameter name
* is {@code "Source"} (as specified in OGC implementation specification) and the alias
* is {@code "source0"} (for compatibility with <cite>Java Advanced Imaging</cite>).
*/
public static final ParameterDescriptor<GridCoverage2D> SOURCE_0;
/**
* Convenience constant for the second source {@link GridCoverage2D}. The parameter name
* is {@code "source1"} (for compatibility with <cite>Java Advanced Imaging</cite>).
*
* @since 3.00
*/
public static final ParameterDescriptor<GridCoverage2D> SOURCE_1;
/**
* Convenience constant for the third source {@link GridCoverage2D}. The parameter name
* is {@code "source2"} (for compatibility with <cite>Java Advanced Imaging</cite>).
*
* @since 3.00
*/
public static final ParameterDescriptor<GridCoverage2D> SOURCE_2;
static {
final Map<String,Object> properties = new HashMap<>(4);
properties.put(IdentifiedObject.NAME_KEY, new NamedIdentifier(Citations.OGC, "Source"));
properties.put(IdentifiedObject.ALIAS_KEY, new NamedIdentifier(Citations.JAI, "source0"));
SOURCE_0 = new DefaultParameterDescriptor<>(properties, GridCoverage2D.class,
null, null, null, null, null, true);
properties.clear();
properties.put(IdentifiedObject.NAME_KEY, new NamedIdentifier(Citations.JAI, "source1"));
SOURCE_1 = new DefaultParameterDescriptor<>(properties, GridCoverage2D.class,
null, null, null, null, null, true);
properties.put(IdentifiedObject.NAME_KEY, new NamedIdentifier(Citations.JAI, "source2"));
SOURCE_2 = new DefaultParameterDescriptor<>(properties, GridCoverage2D.class,
null, null, null, null, null, true);
}
/**
* Constructs an operation. The operation name will be the same than the
* parameter descriptor name.
*
* @param descriptor The parameters descriptor.
*/
protected Operation2D(final ParameterDescriptorGroup descriptor) {
super(descriptor);
}
/**
* Returns the view of {@link GridCoverage2D} to use for computation purpose. The default
* implementation conservatively returns {@link ViewType#GEOPHYSICS} in all case. This is
* a "conservative" implementation because this is often the only view which is guaranteed
* to be mainfull (assuming that a grid coverage has defined such a view). If computation
* should be performed on the data "as is" without any "<cite>samples to geophysics values</cite>"
* conversion, then subclasses should override this method and returns {@link ViewType#SAME}.
*
* @param parameters The parameters supplied by the user to the {@code doOperation} method.
* @return The view on which computation should be performed.
*
* @see GridCoverage2D#view(ViewType)
*
* @since 3.00
*/
protected ViewType getComputationView(final ParameterValueGroup parameters) {
return ViewType.GEOPHYSICS;
}
/**
* Extracts and prepares the sources for this {@code Operation2D}, assuming that the parameters
* use the standard names for the sources. The expected number of sources is the length of the
* {@code sources} array. If this length is 1, then the parameter group is expected to contain
* a parameter named {@code "Source"} with a value of type {@link GridCoverage2D}. If the length
* of the {@code sources} array is greater then 1, then the parameter group is expected to contain
* parameters named {@code "source0"}, {@code "source1"}, ..., <code>"source<var>n</var>"</code>
* where <var>n</var> is the array length.
* <p>
* The source coverages extracted from the parameters are stored in the given {@code sources}
* array, taking into account the need for going to the geophysics view of the data in case
* this operation requires so.
*
* @param parameters
* Parameters that will control this operation.
* @param sources
* The array where to store the {@link GridCoverage2D} to be used as sources
* for this operation.
* @return The view of the result. The {@code doOperation} method should converts its
* result to that view.
* @throws ParameterNotFoundException
* If a required source has not been found.
* @throws InvalidParameterValueException
* If a source doesn't contain a value of type {@link GridCoverage2D}.
*
* @since 3.00
*/
protected ViewType extractSources(final ParameterValueGroup parameters,
final GridCoverage2D[] sources)
throws ParameterNotFoundException, InvalidParameterValueException
{
ensureNonNull("parameters", parameters);
ensureNonNull("sources", sources);
final String[] names = new String[sources.length];
if (sources.length == 1) {
names[0] = "Source";
} else {
final StringBuilder buffer = new StringBuilder("source");
final int length = buffer.length();
for (int i=0; i<sources.length; i++) {
buffer.setLength(length);
names[i] = buffer.append(i).toString();
}
}
return extractSources(parameters, names, sources);
}
/**
* Extracts and prepares the sources for this {@code Operation2D}, knowing that the parameters
* use the given names for the sources. The expected number of sources is the length of the
* {@code names} array. For each name at index <var>i</var>, a parameter having the name
* {@code name[i]} is expected to exist and have a value of type {@link GridCoverage2D}.
* The reference to this coverage is stored in {@code sources[i]} (overwriting any previous
* value), taking into account the need for going to the geophysics view of the data in case
* this operation requires so.
*
* @param parameters
* Parameters that will control this operation.
* @param sourceNames
* Names of the sources to extract from {@link ParameterValueGroup}.
* @param sources
* An array with the same length than {@code sourceNames} where to store
* the {@link GridCoverage2D} to be used as sources for this operation.
* @return The view of the result. The {@code doOperation} method should converts its
* result to that view.
* @throws ParameterNotFoundException
* if a required source has not been found.
* @throws InvalidParameterValueException
* if a source doesn't contain a value of type {@link GridCoverage2D}.
*
* @since 2.4
*/
protected ViewType extractSources(final ParameterValueGroup parameters,
final String[] sourceNames,
final GridCoverage2D[] sources)
throws ParameterNotFoundException, InvalidParameterValueException
{
ensureNonNull("parameters", parameters);
ensureNonNull("sourceNames", sourceNames);
ensureNonNull("sources", sources);
if (sources.length != sourceNames.length) {
throw new IllegalArgumentException(Errors.format(
Errors.Keys.MismatchedArrayLength_2, "sources", "sourceNames"));
}
final ViewType computationView = getComputationView(parameters);
ensureNonNull("computationView", computationView);
ViewType targetView = ViewType.SAME;
for (int i=0; i<sourceNames.length; i++) {
final Object candidate = parameters.parameter(sourceNames[i]).getValue();
if (!(candidate instanceof GridCoverage2D)) {
throw new InvalidParameterValueException(Errors.format(Errors.Keys.IllegalClass_2,
Classes.getClass(candidate), GridCoverage2D.class), sourceNames[i], candidate);
}
final GridCoverage2D old = (GridCoverage2D) candidate;
final GridCoverage2D source = old.view(computationView);
/*
* If we are setting the primary source, and the computation view of that source
* is not the same than the original source coverage, takes the preferred view of
* the output.
*/
if (i == PRIMARY_SOURCE_INDEX && old != source) {
final Set<ViewType> views = old.getViewTypes();
if (views != null) {
for (final ViewType type : PREFERRED_OUTPUTS) {
if (views.contains(type)) {
targetView = type;
break;
}
}
}
}
sources[i] = source;
}
return targetView;
}
/**
* Returns the factory to use for creating new {@link GridCoverage2D} objects.
*
* @param hints An optional set of hints, or {@code null} if none.
* @return The factory to use for creating new {@link GridCoverage2D} objects.
*
* @since 2.2
*/
static GridCoverageFactory getFactory(final Hints hints) {
return CoverageFactoryFinder.getGridCoverageFactory(hints);
}
}