/*
* Geotoolkit - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 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.combineIterator;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import org.apache.sis.geometry.GeneralEnvelope;
import org.apache.sis.referencing.CRS;
import org.geotoolkit.referencing.cs.DiscreteCoordinateSystemAxis;
import org.opengis.geometry.Envelope;
import org.opengis.referencing.crs.CompoundCRS;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.cs.CoordinateSystem;
import org.opengis.referencing.cs.CoordinateSystemAxis;
import org.opengis.referencing.operation.MathTransform;
import org.apache.sis.referencing.CommonCRS;
/**
* Iterator on {@link Envelope} which find all possible dimension combinations upper to 2 dimensions.
*
* @author Cédric Briançon (Geomatys).
* @author Johann Sorel (Geomatys).
* @author Remi Marechal (Geomatys).
* @module
*/
public class CombineIterator implements Iterator<Envelope> {
private final List<List<Comparable>> values;
private final int[] positions;
private final GeneralEnvelope baseEnvelope;
private boolean finish = false;
public CombineIterator(final GeneralEnvelope baseEnvelope) {
final CoordinateReferenceSystem crs = baseEnvelope.getCoordinateReferenceSystem();
final CoordinateSystem cs = crs.getCoordinateSystem();
// Stores additional coordinate system axes, to know how many pyramids should be created
final List<List<Comparable>> possibilities = new ArrayList<List<Comparable>>();
final int nbdim = cs.getDimension();
for (int i = 2; i < nbdim; i++) {
final CoordinateSystemAxis axis = cs.getAxis(i);
if (axis instanceof DiscreteCoordinateSystemAxis) {
final DiscreteCoordinateSystemAxis daxis = (DiscreteCoordinateSystemAxis) axis;
final List<Comparable> values = new ArrayList<Comparable>();
possibilities.add(values);
final int nbval = daxis.length();
for (int k = 0; k < nbval; k++) {
final Comparable c = daxis.getOrdinateAt(k);
values.add(c);
}
}
}
this.values = possibilities;
this.positions = new int[possibilities.size()];
this.baseEnvelope = baseEnvelope;
}
/**
* Defines an iterator on given values with the given base envelope.
*
* @param values Values to iterate. Must not be {@code null}.
* @param baseEnvelope Base envelope. Must not be {@code null}.
*/
public CombineIterator(final List<List<Comparable>> values, final GeneralEnvelope baseEnvelope) {
this.values = values;
this.positions = new int[values.size()];
this.baseEnvelope = baseEnvelope;
}
/**
* {@inheritDoc}
*/
@Override
public Envelope next() {
if (finish) {
return null;
}
for (int i = 0; i < positions.length; i++) {
final Comparable c = values.get(i).get(positions[i]);
Number n;
if(c instanceof Number){
n = (Number) c;
}else if(c instanceof Date){
n = ((Date)c).getTime();
//transform correctly value, unit type might have changed.
final CoordinateReferenceSystem baseCRS = CommonCRS.Temporal.JAVA.crs();
final CoordinateReferenceSystem targetCRS = ((CompoundCRS)baseEnvelope.getCoordinateReferenceSystem()).getComponents().get(1+i);
//try to convert from one axis to the other
try{
final MathTransform trs = CRS.findOperation(baseCRS, targetCRS, null).getMathTransform();
final double[] bv = new double[]{n.doubleValue()};
trs.transform(bv, 0, bv, 0, 1);
n = bv[0];
}catch(Exception ex){
throw new IllegalStateException(ex.getMessage(), ex);
}
}else{
throw new IllegalStateException("Comparable type not supported : "+ c, null);
}
baseEnvelope.setRange(2+i, n.doubleValue(), n.doubleValue());
//prepare next iteration
if (i == positions.length - 1) {
positions[i] = positions[i] + 1;
}
}
//prepare next iteration
for (int i = positions.length - 1; i >= 0; i--) {
if (positions[i] >= values.get(i).size()) {
if (i == 0) {
finish = true;
break;
}
//increment previous, restart this level at zero
positions[i] = 0;
positions[i - 1]++;
}
}
if (positions.length == 0) {
finish = true;
}
return baseEnvelope;
}
/**
* {@inheritDoc}
*/
@Override
public boolean hasNext() {
return !finish;
}
/**
* Not implemented in this implementation.
*/
@Override
public void remove() {
throw new UnsupportedOperationException("Not supported yet.");
}
}