/*
* GeoTools - OpenSource mapping toolkit
* http://geotools.org
* (C) 2002-2006, GeoTools Project Managment Committee (PMC)
*
* 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.geotools.referencing.operation.builder;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.vecmath.MismatchedSizeException;
import org.geotools.geometry.DirectPosition2D;
import org.geotools.geometry.Envelope2D;
import org.geotools.referencing.CRS;
import org.geotools.referencing.operation.DefaultMathTransformFactory;
import org.geotools.referencing.operation.transform.WarpGridTransform2D;
import org.opengis.parameter.ParameterValueGroup;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.TransformException;
import org.opengis.spatialschema.geometry.Envelope;
import org.opengis.spatialschema.geometry.MismatchedDimensionException;
import org.opengis.spatialschema.geometry.MismatchedReferenceSystemException;
/**
* Provides a basic implementation for {@linkplain WarpGridTransform2D warp grid math transform} builders.
*
* @see <A HREF="http://java.sun.com/products/java-media/jai/forDevelopers/jai-apidocs/javax/media/jai/WarpGrid.html">WarpGrid at JAI </A>
*
* @author jezekjan
*
*/
public abstract class WarpGridBuilder extends MathTransformBuilder {
/**
* Grid width
*/
private int width;
/**
* Grid height
*/
private int height;
/**
* Envelope for generated Grid
*/
Envelope envelope;
/**
* List of Mapped Positions in ggrid coordinates
*/
List /*<MappedPosition>*/ localpositions = new ArrayList();
//List /*<MappedPosition>*/ worldpositions ;
/** GridValues like maxx maxt dx dy etc.. */
GridParamValues globalValues;
/** RealToGrid Math Transform */
MathTransform worldToGrid;
/** Grid of x shifts */
private float[][] dxgrid;
/** Grid of y shifts*/
private float[][] dygrid;
/** Warp positions*/
private float[] warpPositions;
/**
* Constructs Builder
* @param vectors Mapped positions
* @param dx The horizontal spacing between grid cells.
* @param dy The vertical spacing between grid cells.
* @param envelope Envelope of generated grid.
* @throws MismatchedSizeException
* @throws MismatchedDimensionException
* @throws MismatchedReferenceSystemException
*/
public WarpGridBuilder(List vectors, double dx, double dy, Envelope envelope,
MathTransform realToGrid)
throws MismatchedSizeException, MismatchedDimensionException,
MismatchedReferenceSystemException, TransformException {
this.worldToGrid = realToGrid;
globalValues = new GridParamValues(envelope, realToGrid, dx, dy);
super.setMappedPositions(vectors);
// super.setMappedPositions(transformMPToGrid(vectors, realToGrid));
localpositions = transformMPToGrid(vectors, realToGrid);
this.envelope = envelope;
}
public List getGridMappedPositions() {
if (localpositions == null) {
localpositions = transformMPToGrid(getMappedPositions(), worldToGrid);
}
return localpositions;
}
/**
* Transforms MappedPostions to grid system
*
*/
private List transformMPToGrid(List MappedPositions, MathTransform trans) {
List gridmp = new ArrayList();
for (Iterator i = MappedPositions.iterator(); i.hasNext();) {
MappedPosition mp = (MappedPosition) i.next();
try {
DirectPosition2D gridSource = new DirectPosition2D();
DirectPosition2D gridTarget = new DirectPosition2D();
trans.transform(mp.getSource(), gridSource);
trans.transform(mp.getTarget(), gridTarget);
gridmp.add(new MappedPosition(gridSource, gridTarget));
} catch (MismatchedDimensionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TransformException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return gridmp;
}
private void ensureVectorsInsideEnvelope() {
/* @TODO - ensure that source MappedPositions are inside the envelope*/
}
/*
*
* (non-Javadoc)
* @see org.geotools.referencing.operation.builder.MathTransformBuilder#computeMathTransform()
*/
protected MathTransform computeMathTransform() throws FactoryException {
warpPositions = getGrid();
globalValues.WarpGridParameters.parameter("warpPositions").setValue(warpPositions);
WarpGridTransform2D wt = (WarpGridTransform2D) (new WarpGridTransform2D.Provider())
.createMathTransform(globalValues.getWarpGridParameters());
wt.setWorldtoGridTransform(this.worldToGrid);
return wt;
}
/*
* (non-Javadoc)
* @see org.geotools.referencing.operation.builder.MathTransformBuilder#getMinimumPointCount()
*/
public int getMinimumPointCount() {
return 1;
}
/**
* Computes WarpGrid Positions.
*
*/
abstract protected float[] computeWarpGrid(ParameterValueGroup values);
/**
* Returs Grid
* @return
*/
private float[] getGrid() {
if (warpPositions == null) {
warpPositions = computeWarpGrid(globalValues.WarpGridParameters);
} else {
return warpPositions;
}
return warpPositions;
}
/**
* Return array of Shifts. This method is useful to create Coverage2D object.
* @return array of Shifts
*/
public float[][] getDxGrid() {
if ((dxgrid == null) || (dxgrid.length == 0)) {
ParameterValueGroup WarpParams = globalValues.WarpGridParameters;
final int xNumCells = WarpParams.parameter("xNumCells").intValue();
final int yNumCells = WarpParams.parameter("yNumCells").intValue();
final int xStep = WarpParams.parameter("xStep").intValue();
final int yStep = WarpParams.parameter("yStep").intValue();
final float[] warpPositions = getGrid();
dxgrid = new float[yNumCells + 1][xNumCells + 1];
for (int i = 0; i <= WarpParams.parameter("yNumCells").intValue(); i++) {
for (int j = 0; j <= WarpParams.parameter("xNumCells").intValue(); j++) {
dxgrid[i][j] = (float) warpPositions[(int) ((i * (1 + xNumCells) * 2) + (2 * j))]
- (j * xStep);
}
}
}
return dxgrid;
}
/**
* Return array of Shifts. This method is useful to create Coverage2D object.
* @return array of Shifts
*/
public float[][] getDyGrid() {
if ((dygrid == null) || (dygrid.length == 0)) {
ParameterValueGroup WarpParams = globalValues.WarpGridParameters;
final int xNumCells = WarpParams.parameter("xNumCells").intValue();
final int yNumCells = WarpParams.parameter("yNumCells").intValue();
final int xStep = WarpParams.parameter("xStep").intValue();
final int yStep = WarpParams.parameter("yStep").intValue();
final float[] warpPositions = getGrid();
dygrid = new float[yNumCells + 1][xNumCells + 1];
for (int i = 0; i <= WarpParams.parameter("yNumCells").intValue(); i++) {
for (int j = 0; j <= WarpParams.parameter("xNumCells").intValue(); j++) {
dygrid[i][j] = (float) warpPositions[(int) ((i * (1 + xNumCells) * 2) + (2 * j)
+ 1)] - (i * yStep);
}
}
}
return dygrid;
}
/**
*
* @param dim
* @param path
* @return
* @throws IOException
*/
public File getDeltaFile(int dim, String path) throws IOException {
ParameterValueGroup WarpParams = globalValues.WarpGridParameters;
final float[] warpPositions = (float[]) WarpParams.parameter("warpPositions").getValue();
File file = new File(path);
FileOutputStream fos = new FileOutputStream(file);
OutputStreamWriter osw = new OutputStreamWriter(fos);
/*Print the header*/
osw.write("Warp Grid transformation");
osw.write("\n");
/*Print first row (number of columns, number of rows,
* number of z–values (always one), minimum longitude, cell
* size, minimum latitude, cell size, and not used. )*/
osw.write((WarpParams.parameter("xNumCells").intValue()+1) + " "
+ (WarpParams.parameter("yNumCells").intValue()+1) + " " + "1 "
+ WarpParams.parameter("xStart").doubleValue() + " "
+ WarpParams.parameter("xStep").doubleValue() + " "
+ WarpParams.parameter("yStart").doubleValue() + " "
+ WarpParams.parameter("yStep").doubleValue() + " 0");
//osw.write("\n");
int ii = 0;
if (dim == 0) {
for (int i = 0; i < getDxGrid().length; i++) {
osw.write(String.valueOf("\n"));
for (int j = 0; j < getDxGrid()[i].length; j++) {
osw.write(String.valueOf(getDxGrid()[i][j]) + " ");
}
}
} else if (dim == 1) {
for (int i = 0; i < getDxGrid().length; i++) {
osw.write(String.valueOf("\n"));
for (int j = 0; j < getDxGrid()[i].length; j++) {
osw.write(String.valueOf(getDyGrid()[i][j]) + " ");
}
}
} else {
throw new IndexOutOfBoundsException(Double.toString(dim));
}
osw.close();
return file;
}
/**
* Converts warp positions from float[] containing target
* positions to float[][] containing deltas.
*
*/
public static void warpPosToDeltas(int xStart, int xStep, int xNumCells, int yStart, int yStep, int yNumCells, float[][] yDeltas, float[][] xDeltas){
}
public static float[] deltasToWarpPos(int xStart, int xStep, int xNumCells, int yStart, int yStep, int yNumCells, float[][] yDeltas, float[][] xDeltas){
float[] warpPos = new float[(xNumCells+1)*(yNumCells+1)*2];
for (int i = 0; i < yNumCells; i++) {
for (int j = 0; j < xNumCells; j++) {
warpPos[2*j+xNumCells*i*2] = xStart + j*xStep +xDeltas[i][j];
warpPos[2*j+xNumCells*i*2 +1 ] = yStart + i*yStep + yDeltas[i][j];
}
}
return warpPos;
}
/**
* Takes care about parameters
* @author jezekjan
*
*/
private static class GridParamValues {
private ParameterValueGroup WarpGridParameters;
/**
* Constructs GridParamValues from such properties.
* @param env Envelope
* @param trans Transformation to Grid CRS.
* @param dx x step
* @param dy y step
* @throws TransformException
*/
public GridParamValues(Envelope env, MathTransform trans, double dx, double dy)
throws TransformException {
Envelope dxdy = new Envelope2D(((Envelope2D)env).getCoordinateReferenceSystem(), env.getMinimum(0),
env.getMinimum(1), dx, dy);
/* Transforms dx, dy and envelope to grid system */
// dxdy = CRS.transform(trans, dxdy);
// env = CRS.transform(trans, env);
try {
final DefaultMathTransformFactory factory = new DefaultMathTransformFactory();
WarpGridParameters = factory.getDefaultParameters("Warp Grid");
WarpGridParameters.parameter("xStart").setValue((int) (env.getMinimum(0) + 0.5));
WarpGridParameters.parameter("yStart").setValue((int) (env.getMinimum(1) + 0.5));
WarpGridParameters.parameter("xStep").setValue((int) Math.ceil(dxdy.getLength(0)));
WarpGridParameters.parameter("yStep").setValue((int) Math.ceil(dxdy.getLength(1)));
WarpGridParameters.parameter("xNumCells")
.setValue((int) Math.ceil(env.getLength(0) / dxdy.getLength(0)));
WarpGridParameters.parameter("yNumCells")
.setValue((int) Math.ceil(env.getLength(1) / dxdy.getLength(1)));
WarpGridParameters.parameter("warpPositions")
.setValue(new float[2 * (WarpGridParameters.parameter("xNumCells")
.intValue() + 1) * (WarpGridParameters.parameter(
"yNumCells").intValue() + 1)]);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Sets the grid warp positions in
* @param warpPos array of grid warp positions
*/
public void setGridWarpPostions(float[] warpPos) {
WarpGridParameters.parameter("warpPositions").setValue(warpPos);
}
/**
* Returns warp grid positions.
* @return warp grid positions
*/
public ParameterValueGroup getWarpGridParameters() {
return WarpGridParameters;
}
}
}