/*
* Geotoolkit.org - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2010-2012, Open Source Geospatial Foundation (OSGeo)
* (C) 2010-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.referencing.cs;
import java.util.List;
import java.util.Arrays;
import org.opengis.referencing.cs.CoordinateSystem;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.crs.CompoundCRS;
import org.opengis.referencing.operation.MathTransform;
import org.geotoolkit.lang.Decorator;
import org.geotoolkit.resources.Errors;
import org.apache.sis.internal.util.UnmodifiableArrayList;
import org.apache.sis.referencing.operation.transform.MathTransforms;
/**
* An implementation of {@link CompoundCRS} delegating every method calls to the wrapped CRS,
* except the coordinate system.
*
* @author Martin Desruisseaux (Geomatys)
* @version 3.16
*
* @since 3.15
* @module
*/
@Decorator(CompoundCRS.class)
final class DiscreteCompoundCRS extends DiscreteCRS<CompoundCRS> implements CompoundCRS {
/**
* For cross-version compatibility.
*/
private static final long serialVersionUID = -4292250243969805179L;
/**
* The CRS components.
*/
private final List<CoordinateReferenceSystem> components;
/**
* Creates a new compound CRS wrapping the given CRS with the given components.
*/
private DiscreteCompoundCRS(final CompoundCRS crs, final DiscreteCS cs,
final CoordinateReferenceSystem[] components)
{
super(crs, cs);
this.components = UnmodifiableArrayList.wrap(components);
}
/**
* Returns the components CRS as an unmodifiable list.
*/
@Override
public List<CoordinateReferenceSystem> getComponents() {
return components;
}
/**
* Returns a CRS instance wrapping the given CRS with the given ordinate values for each axis.
*
* @param crs The coordinate reference system to wrap.
* @param ordinates The ordinate values for each axis. The arrays are <strong>not</strong> cloned.
* @return A new coordinate reference system wrapping the given one with discrete axes.
* @throws IllegalArgumentException If the length of the {@code ordinates} array is not equals
* to the coordinate system {@linkplain CoordinateSystem#getDimension() dimension}.
*/
static CompoundCRS create(final CompoundCRS crs, final double[]... ordinates) {
/*
* Get the CRS components. For each components, there is a choice:
*
* 1) If the component is not discrete, replace it by a new discrete component CRS.
*
* 2) Otherwise, make sure that the axes in the component CRS are equal to the axis
* in the CompoundCRS as a whole. This consistency check is required for NetcdfCRS,
* which may have temporarily an inconsistent CRS.
*/
final List<CoordinateReferenceSystem> source = crs.getComponents();
final CoordinateReferenceSystem[] components = new CoordinateReferenceSystem[source.size()];
final CoordinateSystem cs = crs.getCoordinateSystem();
boolean changed = false;
int lower = 0;
for (int i=0; i<components.length; i++) {
final CoordinateReferenceSystem component = source.get(i);
final int upper = lower + component.getCoordinateSystem().getDimension();
components[i] = DiscreteReferencingFactory.createDiscreteCRS(
component, Arrays.copyOfRange(ordinates, lower, upper));
if (!changed) {
if (components[i] != component) {
// A non-discrete CRS has been replaced by a discrete CRS (case 1 above).
changed = true;
} else {
// Ensure that the axes are consistent (case 2 above).
final CoordinateSystem ccs = components[i].getCoordinateSystem();
final int dimension = ccs.getDimension();
for (int j=0; j<dimension; j++) {
if (!ccs.getAxis(j).equals(cs.getAxis(lower + j))) {
changed = true;
break;
}
}
}
}
lower = upper;
}
if (!changed) {
// Current instance already have the given ordinate values.
return crs;
}
/*
* At this point, we have a list of CRS components where each components have discrete
* axis. Now get the list of those axes in order to build a new discrete CS. Note that
* it would be a bug if an axis is not an instance of DiscreteCoordinateSystemAxis.
*/
final DiscreteCoordinateSystemAxis<?>[] axes = new DiscreteCoordinateSystemAxis<?>[cs.getDimension()];
int count = 0;
for (int i=0; i<components.length; i++) {
final CoordinateSystem component = components[i].getCoordinateSystem();
final int dimension = component.getDimension();
for (int j=0; j<dimension; j++) {
if (count < axes.length) {
// Following cast should never fail.
axes[count] = (DiscreteCoordinateSystemAxis<?>) component.getAxis(j);
}
count++;
}
}
if (count != axes.length) {
throw new IllegalArgumentException(Errors.format(
Errors.Keys.MismatchedDimension_2, axes.length, count));
}
return new DiscreteCompoundCRS(crs, new DiscreteCS(cs, axes), components);
}
/**
* Returns the transform from grid coordinates to CRS coordinates mapping pixel center.
* This method delegates to each component, because some component may compute their own
* transform in a different way than {@link DiscreteReferencingFactory#getAffineTransform}.
* For example {@link org.geotoolkit.referencing.adapters.NetcdfCRS} returns {@code null}
* if an axis is irregular.
*/
@Override
public synchronized MathTransform getGridToCRS() {
if (gridToCRS == null) {
gridToCRS = MathTransforms.linear(DiscreteReferencingFactory.getAffineTransform(this, cs.axes));
}
return gridToCRS;
}
}