/*---------------- FILE HEADER ------------------------------------------
This file is part of deegree.
Copyright (C) 2001 by:
EXSE, Department of Geography, University of Bonn
http://www.giub.uni-bonn.de/exse/
lat/lon GmbH
http://www.lat-lon.de
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; either
version 2.1 of the License, or (at your option) any later version.
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.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact:
Andreas Poth
lat/lon GmbH
Aennchenstr. 19
53115 Bonn
Germany
E-Mail: poth@lat-lon.de
Klaus Greve
Department of Geography
University of Bonn
Meckenheimer Allee 166
53115 Bonn
Germany
E-Mail: klaus.greve@uni-bonn.de
---------------------------------------------------------------------------*/
package org.deegree.model.crs;
import java.awt.image.BufferedImage;
import java.awt.image.renderable.ParameterBlock;
import java.util.Locale;
import javax.media.jai.Interpolation;
import javax.media.jai.InterpolationNearest;
import javax.media.jai.JAI;
import javax.media.jai.WarpPolynomial;
import org.deegree.graphics.transformation.GeoTransform;
import org.deegree.graphics.transformation.WorldToScreenTransform;
import org.deegree.i18n.Messages;
import org.deegree.model.coverage.grid.AbstractGridCoverage;
import org.deegree.model.coverage.grid.ImageGridCoverage;
import org.deegree.model.csct.cs.ConvenienceCSFactory;
import org.deegree.model.csct.cs.CoordinateSystem;
import org.deegree.model.csct.ct.CoordinateTransformationFactory;
import org.deegree.model.csct.ct.MathTransform;
import org.deegree.model.feature.Feature;
import org.deegree.model.feature.FeatureCollection;
import org.deegree.model.feature.FeatureProperty;
import org.deegree.model.spatialschema.Curve;
import org.deegree.model.spatialschema.CurveSegment;
import org.deegree.model.spatialschema.Envelope;
import org.deegree.model.spatialschema.Geometry;
import org.deegree.model.spatialschema.GeometryException;
import org.deegree.model.spatialschema.GeometryFactory;
import org.deegree.model.spatialschema.MultiCurve;
import org.deegree.model.spatialschema.MultiPoint;
import org.deegree.model.spatialschema.MultiSurface;
import org.deegree.model.spatialschema.Point;
import org.deegree.model.spatialschema.Position;
import org.deegree.model.spatialschema.Surface;
import org.deegree.model.spatialschema.SurfacePatch;
import org.deegree.ogcwebservices.wcs.describecoverage.CoverageOffering;
import org.deegree.ogcwebservices.wcs.describecoverage.DomainSet;
import org.opengis.coverage.grid.GridCoverage;
import org.opengis.pt.PT_CoordinatePoint;
/**
* class for transforming deegree geometries to new coordinate
* reference systems.
*
* <p>------------------------------------------------------------</p>
*
* @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
* @version $Revision: 1.13 $ $Date: 2006/12/03 21:20:15 $
*/
public class GeoTransformer implements IGeoTransformer {
private ConvenienceCSFactory csFactory = null;
private CoordinateSystem targetCS = null;
/**
* Creates a new GeoTransformer object.
*
* @param targetCS
*
* @throws Exception
*/
public GeoTransformer( String targetCS ) {
csFactory = ConvenienceCSFactory.getInstance();
this.targetCS = csFactory.getCSByName( targetCS );
}
/**
* Creates a new GeoTransformer object.
*
* @param targetCS
* @throws Exception
*/
public GeoTransformer( org.deegree.model.crs.CoordinateSystem targetCRS ) {
csFactory = ConvenienceCSFactory.getInstance();
this.targetCS = csFactory.getCSByName( targetCRS.getName() );
}
/* (non-Javadoc)
* @see org.deegree.model.crs.IGeoTransformer#transform(org.deegree.model.spatialschema.Geometry)
*/
public Geometry transform( Geometry geo )
throws CRSTransformationException {
CoordinateSystem cs = ConvenienceCSFactory.getInstance().getCSByName(
geo.getCoordinateSystem().getName() );
CoordinateTransformationFactory ctfc = CoordinateTransformationFactory.getDefault();
MathTransform trans = null;
try {
trans = ctfc.createFromCoordinateSystems( cs, targetCS ).getMathTransform();
} catch ( Exception e ) {
e.printStackTrace();
String s = Messages.getMessage( "CRS_NOT_SUPPORTED_TRANSFORMATION",
geo.getCoordinateSystem(), targetCS, e.getMessage() );
throw new CRSTransformationException( s );
}
if ( geo instanceof Point ) {
geo = transform( (Point) geo, trans );
} else if ( geo instanceof Curve ) {
geo = transform( (Curve) geo, trans );
} else if ( geo instanceof Surface ) {
geo = transform( (Surface) geo, trans );
} else if ( geo instanceof MultiPoint ) {
geo = transform( (MultiPoint) geo, trans );
} else if ( geo instanceof MultiCurve ) {
geo = transform( (MultiCurve) geo, trans );
} else if ( geo instanceof MultiSurface ) {
geo = transform( (MultiSurface) geo, trans );
}
return geo;
}
/**
* transforms the submitted point to the target coordinate reference system
*/
private Geometry transform( Point geo, MathTransform trans )
throws CRSTransformationException {
try {
double[] din = geo.getAsArray();
if ( geo.getCoordinateSystem().getUnits().equals( "°" ) ) {
if ( din[0] <= -179.999 )
din[0] = -179.999;
else if ( din[0] >= 179.999 )
din[0] = 179.999;
if ( din[1] <= -89.999 )
din[1] = -89.999;
else if ( din[1] >= 89.999 )
din[1] = 89.999;
}
double[] di = new double[] { din[0], din[1] };
double[] dou = new double[2];
trans.transform( di, 0, dou, 0, di.length - 1 );
org.deegree.model.crs.CoordinateSystem crs = CRSFactory.create( targetCS.getName( Locale.getDefault() ) );
geo = GeometryFactory.createPoint( dou[0], dou[1], din[2], crs );
} catch ( Exception e ) {
e.printStackTrace();
throw new CRSTransformationException( e );
}
return geo;
}
/**
* transforms the submitted curve to the target coordinate reference system
*/
private Geometry transform( Curve geo, MathTransform trans )
throws CRSTransformationException {
try {
CurveSegment[] newcus = new CurveSegment[geo.getNumberOfCurveSegments()];
org.deegree.model.crs.CoordinateSystem crs = CRSFactory.create( targetCS.getName( Locale.getDefault() ) );
for ( int i = 0; i < geo.getNumberOfCurveSegments(); i++ ) {
CurveSegment cus = geo.getCurveSegmentAt( i );
Position[] pos = cus.getPositions();
pos = transform( pos, trans );
newcus[i] = GeometryFactory.createCurveSegment( pos, crs );
}
geo = GeometryFactory.createCurve( newcus );
} catch ( Exception e ) {
throw new CRSTransformationException( e );
}
return geo;
}
/**
* transforms the submitted surface to the target coordinate reference system
*/
private Geometry transform( Surface geo, MathTransform trans )
throws CRSTransformationException {
try {
int cnt = geo.getNumberOfSurfacePatches();
SurfacePatch[] patches = new SurfacePatch[cnt];
org.deegree.model.crs.CoordinateSystem crs = CRSFactory.create( targetCS.getName( Locale.getDefault() ) );
for ( int i = 0; i < cnt; i++ ) {
SurfacePatch p = geo.getSurfacePatchAt( i );
Position[] ex = p.getExteriorRing();
ex = transform( ex, trans );
Position[][] in = p.getInteriorRings();
Position[][] inn = null;
if ( in != null ) {
inn = new Position[in.length][];
for ( int k = 0; k < in.length; k++ ) {
inn[k] = transform( in[k], trans );
}
}
patches[i] = GeometryFactory.createSurfacePatch( ex, inn, p.getInterpolation(), crs );
}
// at the moment only polygons made of one patch are supported
geo = GeometryFactory.createSurface( patches[0] );
} catch ( Exception e ) {
e.printStackTrace();
throw new CRSTransformationException( e );
}
return geo;
}
/**
* transforms the submitted multi point to the target coordinate reference
* system
*/
private Geometry transform( MultiPoint geo, MathTransform trans )
throws CRSTransformationException {
try {
Point[] points = new Point[geo.getSize()];
for ( int i = 0; i < geo.getSize(); i++ ) {
points[i] = (Point) transform( geo.getPointAt( i ), trans );
}
geo = GeometryFactory.createMultiPoint( points );
} catch ( Exception e ) {
throw new CRSTransformationException( e );
}
return geo;
}
/**
* transforms the submitted multi curve to the target coordinate reference
* system
*/
private Geometry transform( MultiCurve geo, MathTransform trans )
throws CRSTransformationException {
try {
Curve[] curves = new Curve[geo.getSize()];
for ( int i = 0; i < geo.getSize(); i++ ) {
curves[i] = (Curve) transform( geo.getCurveAt( i ), trans );
}
geo = GeometryFactory.createMultiCurve( curves );
} catch ( Exception e ) {
throw new CRSTransformationException( e );
}
return geo;
}
/**
* transforms the submitted multi surface to the target coordinate reference
* system
*/
private Geometry transform( MultiSurface geo, MathTransform trans )
throws CRSTransformationException {
Surface[] surfaces = new Surface[geo.getSize()];
for ( int i = 0; i < geo.getSize(); i++ ) {
surfaces[i] = (Surface) transform( geo.getSurfaceAt( i ), trans );
}
geo = GeometryFactory.createMultiSurface( surfaces );
return geo;
}
/**
* transfroms an array of Positions to the target coordinate reference
* system
*/
private Position[] transform( Position[] pos, MathTransform trans )
throws Exception {
Position[] newpos = new Position[pos.length];
for ( int k = 0; k < pos.length; k++ ) {
double[] din = pos[k].getAsArray();
double[] di = new double[] { din[0], din[1] };
double[] dou = new double[2];
trans.transform( di, 0, dou, 0, di.length - 1 );
newpos[k] = GeometryFactory.createPosition( dou[0], dou[1], din[2] );
}
return newpos;
}
/* (non-Javadoc)
* @see org.deegree.model.crs.IGeoTransformer#transform(org.deegree.model.spatialschema.Envelope, java.lang.String)
*/
public Envelope transform( Envelope envelope, String sourceCRS )
throws CRSTransformationException {
org.deegree.model.crs.CoordinateSystem crs = null;
try {
crs = CRSFactory.create( sourceCRS );
} catch ( Exception e ) {
e.printStackTrace();
}
return transform( envelope, crs );
}
/* (non-Javadoc)
* @see org.deegree.model.crs.IGeoTransformer#transform(org.deegree.model.spatialschema.Envelope, org.deegree.model.crs.CoordinateSystem)
*/
public Envelope transform( Envelope envelope, org.deegree.model.crs.CoordinateSystem sourceCRS )
throws CRSTransformationException {
Point min = GeometryFactory.createPoint( envelope.getMin().getX(),
envelope.getMin().getY(), sourceCRS );
Point max = GeometryFactory.createPoint( envelope.getMax().getX(),
envelope.getMax().getY(), sourceCRS );
min = (Point) transform( min );
max = (Point) transform( max );
org.deegree.model.crs.CoordinateSystem crs = null;
try {
crs = CRSFactory.create( targetCS.getName( Locale.getDefault() ) );
} catch ( Exception e ) {
e.printStackTrace();
}
// create bounding box with coordinates
return GeometryFactory.createEnvelope( min.getX(), min.getY(), max.getX(), max.getY(), crs );
}
/* (non-Javadoc)
* @see org.deegree.model.crs.IGeoTransformer#transform(org.deegree.model.feature.FeatureCollection)
*/
public FeatureCollection transform( FeatureCollection fc )
throws CRSTransformationException, GeometryException {
for ( int i = 0; i < fc.size(); i++ ) {
transform( fc.getFeature( i ) );
}
return fc;
}
/* (non-Javadoc)
* @see org.deegree.model.crs.IGeoTransformer#transform(org.deegree.model.feature.Feature)
*/
public Feature transform( Feature feature )
throws CRSTransformationException, GeometryException {
org.deegree.model.crs.CoordinateSystem crs = null;
try {
crs = CRSFactory.create( targetCS.getName( Locale.getDefault() ) );
} catch ( Exception e ) {
}
FeatureProperty[] fp = feature.getProperties();
for ( int i = 0; i < fp.length; i++ ) {
if ( fp[i].getValue() instanceof Geometry ) {
Geometry geom = (Geometry) fp[i].getValue();
if ( !crs.equals( geom.getCoordinateSystem() ) ) {
fp[i].setValue( transform( (Geometry) fp[i].getValue() ) );
}
} else if ( fp[i].getValue() instanceof Feature ) {
transform( (Feature) fp[i].getValue() );
}
}
return feature;
}
/* (non-Javadoc)
* @see org.deegree.model.crs.IGeoTransformer#transform(GridCoverage coverage, int refPointsGridSize, int degree)
*/
public GridCoverage transform( AbstractGridCoverage coverage, int refPointsGridSize,
int degree, Interpolation interpolation )
throws CRSTransformationException {
BufferedImage img = coverage.getAsImage( -1, -1 );
PT_CoordinatePoint min = coverage.getEnvelope().minCP;
PT_CoordinatePoint max = coverage.getEnvelope().maxCP;
// create transformation object to transform reference points
// from the source (native) CRS to the target CRS
org.deegree.model.crs.CoordinateSystem crs = coverage.getCoordinateReferenceSystem();
Envelope sourceBBOX = GeometryFactory.createEnvelope( min.ord[0], min.ord[1], max.ord[0],
max.ord[1], crs );
Envelope targetBBOX = transform( sourceBBOX, crs );
GeoTransform sourceGT = new WorldToScreenTransform( sourceBBOX.getMin().getX(),
sourceBBOX.getMin().getY(),
sourceBBOX.getMax().getX(),
sourceBBOX.getMax().getY(), 0, 0,
img.getWidth() - 1, img.getHeight() - 1 );
GeoTransform targetGT = new WorldToScreenTransform( targetBBOX.getMin().getX(),
targetBBOX.getMin().getY(),
targetBBOX.getMax().getX(),
targetBBOX.getMax().getY(), 0, 0,
img.getWidth() - 1, img.getHeight() - 1 );
// create/calculate reference points
float dx = img.getWidth() / (float) ( refPointsGridSize - 1 );
float dy = img.getHeight() / (float) ( refPointsGridSize - 1 );
float[] srcCoords = new float[refPointsGridSize * refPointsGridSize * 2];
float[] targetCoords = new float[refPointsGridSize * refPointsGridSize * 2];
int k = 0;
for ( int i = 0; i < refPointsGridSize; i++ ) {
for ( int j = 0; j < refPointsGridSize; j++ ) {
srcCoords[k] = i * dx;
srcCoords[k + 1] = j * dy;
double x = sourceGT.getSourceX( srcCoords[k] );
double y = sourceGT.getSourceY( srcCoords[k + 1] );
Point point = GeometryFactory.createPoint( x, y, crs );
point = (Point) transform( point );
targetCoords[k] = (float) targetGT.getDestX( point.getX() );
targetCoords[k + 1] = (float) targetGT.getDestY( point.getY() );
k += 2;
}
}
// create warp object from reference points and desired interpolation
WarpPolynomial warp = WarpPolynomial.createWarp( srcCoords, 0, targetCoords, 0,
srcCoords.length, 1f, 1f, 1f, 1f, degree );
if ( interpolation == null ) {
interpolation = new InterpolationNearest();
}
// Create and perform the warp operation.
ParameterBlock pb = new ParameterBlock();
pb.addSource( img );
pb.add( warp );
pb.add( interpolation );
img = JAI.create( "warp", pb ).getAsBufferedImage();
// create a new GridCoverage from the warp result.
// because warping only can be performed on images the
// resulting GridCoverage will be an instance of ImageGridCoverage
CoverageOffering oldCO = coverage.getCoverageOffering();
CoverageOffering coverageOffering = null;
if ( oldCO != null ) {
try {
DomainSet ds = oldCO.getDomainSet();
ds.getSpatialDomain().setEnvelops( new Envelope[] { targetBBOX } );
coverageOffering = new CoverageOffering( oldCO.getName(), oldCO.getLabel(),
oldCO.getDescription(),
oldCO.getMetadataLink(),
oldCO.getLonLatEnvelope(),
oldCO.getKeywords(), ds,
oldCO.getRangeSet(), oldCO.getSupportedCRSs(),
oldCO.getSupportedFormats(),
oldCO.getSupportedInterpolations(),
oldCO.getExtension() );
} catch ( Exception e ) {
String s = Messages.getMessage( "CRS_CO_CREATION_ERROR", e.getMessage() );
throw new CRSTransformationException( s );
}
}
return new ImageGridCoverage( coverageOffering, sourceBBOX, img );
}
}