/*
* Geotoolkit.org - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2014, 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.geometry;
import java.util.Arrays;
import java.util.Iterator;
import java.util.NoSuchElementException;
import org.geotoolkit.geometry.HyperCubeIterator.HyperCube;
import org.opengis.coverage.grid.GridEnvelope;
/**
* Iterator over an hypercube, will iterate on all dimensions of the hypercube
* returning a smaller hypercube each time. the maximum size is given in the constructor.
*
* @author Johann Sorel (Geomatys)
*/
public class HyperCubeIterator implements Iterator<HyperCube>{
private final int[] maxSize;
private final int nbDim;
private final int[] corner;
private final int[] mins;
private final int[] maxs;
private HyperCube next = null;
/**
*
* @param mins hypercube lower corner, inclusive
* @param maxs hypercube upper corner, exclusive
* @param maxSize maximum size of the iteration hypercube
*/
public HyperCubeIterator(int[] mins, int[] maxs, int[] maxSize) {
this.maxSize = maxSize;
this.nbDim = mins.length;
this.mins = mins;
this.maxs = maxs;
//place corner on the minimum
this.corner = new int[nbDim];
System.arraycopy(mins, 0, corner, 0, nbDim);
}
@Override
public boolean hasNext() {
findNext();
return next != null;
}
@Override
public HyperCube next() {
findNext();
if(next==null){
throw new NoSuchElementException("No more elements.");
}
HyperCube t = next;
next = null;
return t;
}
@Override
public void remove() {
throw new UnsupportedOperationException("Not supported.");
}
private void findNext(){
if(next!=null) return;
if(corner[nbDim-1] >= maxs[nbDim-1]){
//nothing left
return;
}
final int[] lower = new int[nbDim];
final int[] upper = new int[nbDim];
for(int i=0;i<nbDim;i++){
lower[i] = corner[i];
upper[i] = corner[i] + maxSize[i];
//ensure the upper value is not greater then the data limit.
if(upper[i]>=maxs[i]) upper[i] = maxs[i];
}
//prepare next iteration
for(int k=0;k<nbDim;k++){
corner[k] += maxSize[k];
if(k<nbDim-1 && corner[k]>=maxs[k]){
//we are too far on this axis
//return to minimum and increment next dimension
corner[k] = mins[k];
}else{
break;
}
}
next = new HyperCube(lower, upper);
}
public static class HyperCube{
private final int[] lower;
private final int[] upper;
/**
*
* @param lower corner, inclusive
* @param upper corner, exclusive
*/
public HyperCube(int[] lower, int[] upper) {
this.lower = lower;
this.upper = upper;
}
/**
*
* @return lower corner, inclusive
*/
public int[] getLower() {
return lower;
}
/**
*
* @return upper corner, exclusive
*/
public int[] getUpper() {
return upper;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final HyperCube other = (HyperCube) obj;
if (!Arrays.equals(this.lower, other.lower)) {
return false;
}
if (!Arrays.equals(this.upper, other.upper)) {
return false;
}
return true;
}
@Override
public String toString() {
return "HyperCube "+Arrays.toString(lower)+" "+Arrays.toString(upper);
}
}
/**
* Create an iterator from GridEnvelope.
* @param gridEnv envelope to iterate in
* @param maxSize maximum size of the iteration hypercube
* @return HyperCubeIterator
*/
public static HyperCubeIterator create(GridEnvelope gridEnv, int[] maxSize) {
final int nbDim = gridEnv.getDimension();
final int[] mins = new int[nbDim];
final int[] maxs = new int[nbDim];
for(int i=0;i<nbDim;i++){
mins[i] = gridEnv.getLow(i);
maxs[i] = gridEnv.getHigh(i)+1; //high value is inclusive in grid envelopes
}
return new HyperCubeIterator(mins, maxs, maxSize);
}
}