001 //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/model/crs/GeoTransformer.java $ 002 /*---------------- FILE HEADER ------------------------------------------ 003 004 This file is part of deegree. 005 Copyright (C) 2001-2007 by: 006 lat/lon GmbH 007 http://www.lat-lon.de 008 009 This library is free software; you can redistribute it and/or 010 modify it under the terms of the GNU Lesser General Public 011 License as published by the Free Software Foundation; either 012 version 2.1 of the License, or (at your option) any later version. 013 014 This library is distributed in the hope that it will be useful, 015 but WITHOUT ANY WARRANTY; without even the implied warranty of 016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 017 Lesser General Public License for more details. 018 019 You should have received a copy of the GNU Lesser General Public 020 License along with this library; if not, write to the Free Software 021 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 022 023 Contact: 024 025 Andreas Poth 026 lat/lon GmbH 027 Aennchenstr. 19 028 53115 Bonn 029 Germany 030 E-Mail: poth@lat-lon.de 031 032 Klaus Greve 033 Department of Geography 034 University of Bonn 035 Meckenheimer Allee 166 036 53115 Bonn 037 Germany 038 E-Mail: klaus.greve@uni-bonn.de 039 040 041 ---------------------------------------------------------------------------*/ 042 package org.deegree.model.crs; 043 044 import java.awt.image.BufferedImage; 045 import java.awt.image.renderable.ParameterBlock; 046 047 import javax.media.jai.Interpolation; 048 import javax.media.jai.InterpolationNearest; 049 import javax.media.jai.JAI; 050 import javax.media.jai.WarpPolynomial; 051 052 import org.deegree.graphics.transformation.GeoTransform; 053 import org.deegree.graphics.transformation.WorldToScreenTransform; 054 import org.deegree.i18n.Messages; 055 import org.deegree.model.coverage.grid.AbstractGridCoverage; 056 import org.deegree.model.coverage.grid.GridCoverage; 057 import org.deegree.model.coverage.grid.ImageGridCoverage; 058 import org.deegree.model.csct.cs.CoordinateSystem; 059 import org.deegree.model.csct.ct.CoordinateTransformationFactory; 060 import org.deegree.model.csct.ct.MathTransform; 061 import org.deegree.model.feature.Feature; 062 import org.deegree.model.feature.FeatureCollection; 063 import org.deegree.model.feature.FeatureProperty; 064 import org.deegree.model.spatialschema.Curve; 065 import org.deegree.model.spatialschema.CurveSegment; 066 import org.deegree.model.spatialschema.Envelope; 067 import org.deegree.model.spatialschema.Geometry; 068 import org.deegree.model.spatialschema.GeometryException; 069 import org.deegree.model.spatialschema.GeometryFactory; 070 import org.deegree.model.spatialschema.MultiCurve; 071 import org.deegree.model.spatialschema.MultiPoint; 072 import org.deegree.model.spatialschema.MultiSurface; 073 import org.deegree.model.spatialschema.Point; 074 import org.deegree.model.spatialschema.Position; 075 import org.deegree.model.spatialschema.Surface; 076 import org.deegree.model.spatialschema.SurfacePatch; 077 import org.deegree.ogcwebservices.wcs.describecoverage.CoverageOffering; 078 import org.deegree.ogcwebservices.wcs.describecoverage.DomainSet; 079 import org.opengis.pt.PT_CoordinatePoint; 080 081 082 /** 083 * class for transforming deegree geometries to new coordinate reference systems. 084 * 085 * <p> 086 * ------------------------------------------------------------ 087 * </p> 088 * 089 * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a> 090 * @author last edited by: $Author: apoth $ 091 * 092 * @version $Revision: 7637 $, $Date: 2007-06-25 13:00:05 +0200 (Mo, 25 Jun 2007) $ 093 */ 094 public class GeoTransformer implements IGeoTransformer { 095 096 private CoordinateSystem targetCS = null; 097 098 private String csAccess = CSAccessFactory.CSA_DEFAULT; 099 100 /** 101 * Creates a new GeoTransformer object. 102 * 103 * @param targetCS 104 * @throws CRSException 105 */ 106 public GeoTransformer( String targetCS ) throws CRSException { 107 this.targetCS = CSAccessFactory.getCSAccess( csAccess ).getCSByCode( targetCS, null ); 108 } 109 110 /** 111 * Creates a new GeoTransformer object. 112 * 113 * @param targetCRS 114 * @throws CRSException 115 */ 116 public GeoTransformer( org.deegree.model.crs.CoordinateSystem targetCRS ) throws CRSException { 117 this.targetCS = CSAccessFactory.getCSAccess( csAccess ).getCSByCode( targetCRS.getName(), null ); 118 } 119 120 /** 121 * Creates a new GeoTransformer object. 122 * 123 * @param targetCS 124 * @throws CRSException 125 */ 126 public GeoTransformer( String targetCS, String csAccess ) throws CRSException { 127 this.csAccess = csAccess; 128 this.targetCS = CSAccessFactory.getCSAccess( csAccess ).getCSByCode( targetCS, null ); 129 } 130 131 /** 132 * Creates a new GeoTransformer object. 133 * 134 * @param targetCRS 135 * @throws CRSException 136 */ 137 public GeoTransformer( org.deegree.model.crs.CoordinateSystem targetCRS, String csAccess ) throws CRSException { 138 this.csAccess = csAccess; 139 this.targetCS = CSAccessFactory.getCSAccess( csAccess ).getCSByCode( targetCRS.getName(), null ); 140 } 141 142 /* 143 * (non-Javadoc) 144 * 145 * @see org.deegree.model.crs.IGeoTransformer#transform(org.deegree.model.spatialschema.Geometry) 146 */ 147 public Geometry transform( Geometry geo ) 148 throws CRSTransformationException, CRSException { 149 150 String csname = geo.getCoordinateSystem().getName(); 151 CoordinateSystem cs = CSAccessFactory.getCSAccess( csAccess ).getCSByCode( csname, null ); 152 153 CoordinateTransformationFactory ctfc = CoordinateTransformationFactory.getDefault(); 154 MathTransform trans = null; 155 156 try { 157 trans = ctfc.createFromCoordinateSystems( cs, targetCS ).getMathTransform(); 158 } catch ( Exception e ) { 159 e.printStackTrace(); 160 String s = Messages.getMessage( "CRS_NOT_SUPPORTED_TRANSFORMATION", 161 geo.getCoordinateSystem(), targetCS, e.getMessage() ); 162 throw new CRSTransformationException( s ); 163 } 164 165 if ( geo instanceof Point ) { 166 geo = transform( (Point) geo, trans ); 167 } else if ( geo instanceof Curve ) { 168 geo = transform( (Curve) geo, trans ); 169 } else if ( geo instanceof Surface ) { 170 geo = transform( (Surface) geo, trans ); 171 } else if ( geo instanceof MultiPoint ) { 172 geo = transform( (MultiPoint) geo, trans ); 173 } else if ( geo instanceof MultiCurve ) { 174 geo = transform( (MultiCurve) geo, trans ); 175 } else if ( geo instanceof MultiSurface ) { 176 geo = transform( (MultiSurface) geo, trans ); 177 } 178 179 return geo; 180 } 181 182 /** 183 * transforms the submitted point to the target coordinate reference system 184 */ 185 private Geometry transform( Point geo, MathTransform trans ) 186 throws CRSTransformationException { 187 188 try { 189 double[] din = geo.getAsArray(); 190 191 if ( geo.getCoordinateSystem().getUnits().equals( "°" ) ) { 192 if ( din[0] <= -179.999 ) 193 din[0] = -179.999; 194 else if ( din[0] >= 179.999 ) 195 din[0] = 179.999; 196 if ( din[1] <= -89.999 ) 197 din[1] = -89.999; 198 else if ( din[1] >= 89.999 ) 199 din[1] = 89.999; 200 } 201 202 double[] di = new double[] { din[0], din[1] }; 203 double[] dou = new double[2]; 204 205 trans.transform( di, 0, dou, 0, di.length - 1 ); 206 207 org.deegree.model.crs.CoordinateSystem crs = CRSFactory.create( targetCS.getName() ); 208 geo = GeometryFactory.createPoint( dou[0], dou[1], din[2], crs ); 209 } catch ( Exception e ) { 210 e.printStackTrace(); 211 throw new CRSTransformationException( e ); 212 } 213 214 return geo; 215 } 216 217 /** 218 * transforms the submitted curve to the target coordinate reference system 219 */ 220 private Geometry transform( Curve geo, MathTransform trans ) 221 throws CRSTransformationException { 222 223 try { 224 CurveSegment[] newcus = new CurveSegment[geo.getNumberOfCurveSegments()]; 225 226 org.deegree.model.crs.CoordinateSystem crs = CRSFactory.create( targetCS.getName() ); 227 for ( int i = 0; i < geo.getNumberOfCurveSegments(); i++ ) { 228 CurveSegment cus = geo.getCurveSegmentAt( i ); 229 Position[] pos = cus.getPositions(); 230 pos = transform( pos, trans ); 231 newcus[i] = GeometryFactory.createCurveSegment( pos, crs ); 232 } 233 234 geo = GeometryFactory.createCurve( newcus ); 235 } catch ( Exception e ) { 236 throw new CRSTransformationException( e ); 237 } 238 239 return geo; 240 } 241 242 /** 243 * transforms the submitted surface to the target coordinate reference system 244 */ 245 private Geometry transform( Surface geo, MathTransform trans ) 246 throws CRSTransformationException { 247 248 try { 249 int cnt = geo.getNumberOfSurfacePatches(); 250 SurfacePatch[] patches = new SurfacePatch[cnt]; 251 252 org.deegree.model.crs.CoordinateSystem crs = CRSFactory.create( targetCS.getName() ); 253 for ( int i = 0; i < cnt; i++ ) { 254 SurfacePatch p = geo.getSurfacePatchAt( i ); 255 Position[] ex = p.getExteriorRing(); 256 ex = transform( ex, trans ); 257 258 Position[][] in = p.getInteriorRings(); 259 Position[][] inn = null; 260 261 if ( in != null ) { 262 inn = new Position[in.length][]; 263 264 for ( int k = 0; k < in.length; k++ ) { 265 inn[k] = transform( in[k], trans ); 266 } 267 } 268 269 patches[i] = GeometryFactory.createSurfacePatch( ex, inn, p.getInterpolation(), crs ); 270 } 271 272 // at the moment only polygons made of one patch are supported 273 geo = GeometryFactory.createSurface( patches[0] ); 274 } catch ( Exception e ) { 275 e.printStackTrace(); 276 throw new CRSTransformationException( e ); 277 } 278 279 return geo; 280 } 281 282 /** 283 * transforms the submitted multi point to the target coordinate reference system 284 */ 285 private Geometry transform( MultiPoint geo, MathTransform trans ) 286 throws CRSTransformationException { 287 288 try { 289 Point[] points = new Point[geo.getSize()]; 290 291 for ( int i = 0; i < geo.getSize(); i++ ) { 292 points[i] = (Point) transform( geo.getPointAt( i ), trans ); 293 } 294 295 geo = GeometryFactory.createMultiPoint( points ); 296 } catch ( Exception e ) { 297 throw new CRSTransformationException( e ); 298 } 299 300 return geo; 301 } 302 303 /** 304 * transforms the submitted multi curve to the target coordinate reference system 305 */ 306 private Geometry transform( MultiCurve geo, MathTransform trans ) 307 throws CRSTransformationException { 308 309 try { 310 Curve[] curves = new Curve[geo.getSize()]; 311 312 for ( int i = 0; i < geo.getSize(); i++ ) { 313 curves[i] = (Curve) transform( geo.getCurveAt( i ), trans ); 314 } 315 316 geo = GeometryFactory.createMultiCurve( curves ); 317 } catch ( Exception e ) { 318 throw new CRSTransformationException( e ); 319 } 320 321 return geo; 322 } 323 324 /** 325 * transforms the submitted multi surface to the target coordinate reference system 326 */ 327 private Geometry transform( MultiSurface geo, MathTransform trans ) 328 throws CRSTransformationException { 329 330 Surface[] surfaces = new Surface[geo.getSize()]; 331 332 for ( int i = 0; i < geo.getSize(); i++ ) { 333 surfaces[i] = (Surface) transform( geo.getSurfaceAt( i ), trans ); 334 } 335 336 geo = GeometryFactory.createMultiSurface( surfaces ); 337 338 return geo; 339 } 340 341 /** 342 * transfroms an array of Positions to the target coordinate reference system 343 */ 344 private Position[] transform( Position[] pos, MathTransform trans ) 345 throws Exception { 346 347 Position[] newpos = new Position[pos.length]; 348 349 for ( int k = 0; k < pos.length; k++ ) { 350 double[] din = pos[k].getAsArray(); 351 double[] di = new double[] { din[0], din[1] }; 352 double[] dou = new double[2]; 353 trans.transform( di, 0, dou, 0, di.length - 1 ); 354 newpos[k] = GeometryFactory.createPosition( dou[0], dou[1], din[2] ); 355 } 356 357 return newpos; 358 } 359 360 /* 361 * (non-Javadoc) 362 * 363 * @see org.deegree.model.crs.IGeoTransformer#transform(org.deegree.model.spatialschema.Envelope, 364 * java.lang.String) 365 */ 366 public Envelope transform( Envelope envelope, String sourceCRS ) 367 throws CRSTransformationException, CRSException { 368 369 org.deegree.model.crs.CoordinateSystem crs = null; 370 try { 371 crs = CRSFactory.create( sourceCRS ); 372 } catch ( Exception e ) { 373 e.printStackTrace(); 374 } 375 return transform( envelope, crs ); 376 } 377 378 /* 379 * (non-Javadoc) 380 * 381 * @see org.deegree.model.crs.IGeoTransformer#transform(org.deegree.model.spatialschema.Envelope, 382 * org.deegree.model.crs.CoordinateSystem) 383 */ 384 public Envelope transform( Envelope envelope, org.deegree.model.crs.CoordinateSystem sourceCRS ) 385 throws CRSTransformationException, CRSException { 386 387 Point min = GeometryFactory.createPoint( envelope.getMin().getX(), 388 envelope.getMin().getY(), sourceCRS ); 389 Point max = GeometryFactory.createPoint( envelope.getMax().getX(), 390 envelope.getMax().getY(), sourceCRS ); 391 min = (Point) transform( min ); 392 max = (Point) transform( max ); 393 394 org.deegree.model.crs.CoordinateSystem crs = null; 395 try { 396 crs = CRSFactory.create( targetCS.getName() ); 397 } catch ( Exception e ) { 398 e.printStackTrace(); 399 } 400 // create bounding box with coordinates 401 return GeometryFactory.createEnvelope( min.getX(), min.getY(), max.getX(), max.getY(), crs ); 402 } 403 404 /* 405 * (non-Javadoc) 406 * 407 * @see org.deegree.model.crs.IGeoTransformer#transform(org.deegree.model.feature.FeatureCollection) 408 */ 409 public FeatureCollection transform( FeatureCollection fc ) 410 throws CRSTransformationException, GeometryException, CRSException { 411 412 for ( int i = 0; i < fc.size(); i++ ) { 413 transform( fc.getFeature( i ) ); 414 } 415 416 return fc; 417 } 418 419 /* 420 * (non-Javadoc) 421 * 422 * @see org.deegree.model.crs.IGeoTransformer#transform(org.deegree.model.feature.Feature) 423 */ 424 public Feature transform( Feature feature ) 425 throws CRSTransformationException, GeometryException, CRSException { 426 427 org.deegree.model.crs.CoordinateSystem crs = null; 428 try { 429 crs = CRSFactory.create( targetCS.getName() ); 430 } catch ( Exception e ) { 431 } 432 FeatureProperty[] fp = feature.getProperties(); 433 for ( int i = 0; i < fp.length; i++ ) { 434 435 if ( fp[i].getValue() instanceof Geometry ) { 436 Geometry geom = (Geometry) fp[i].getValue(); 437 if ( !crs.equals( geom.getCoordinateSystem() ) ) { 438 fp[i].setValue( transform( (Geometry) fp[i].getValue() ) ); 439 } 440 } else if ( fp[i].getValue() instanceof Feature ) { 441 transform( (Feature) fp[i].getValue() ); 442 } 443 444 } 445 446 return feature; 447 } 448 449 /* 450 * (non-Javadoc) 451 * 452 * @see org.deegree.model.crs.IGeoTransformer#transform(GridCoverage coverage, int 453 * refPointsGridSize, int degree) 454 */ 455 public GridCoverage transform( AbstractGridCoverage coverage, int refPointsGridSize, 456 int degree, Interpolation interpolation ) 457 throws CRSTransformationException, CRSException { 458 459 BufferedImage img = coverage.getAsImage( -1, -1 ); 460 PT_CoordinatePoint min = coverage.getEnvelope().minCP; 461 PT_CoordinatePoint max = coverage.getEnvelope().maxCP; 462 463 // create transformation object to transform reference points 464 // from the source (native) CRS to the target CRS 465 org.deegree.model.crs.CoordinateSystem crs = coverage.getCoordinateReferenceSystem(); 466 Envelope sourceBBOX = GeometryFactory.createEnvelope( min.ord[0], min.ord[1], max.ord[0], 467 max.ord[1], crs ); 468 Envelope targetBBOX = transform( sourceBBOX, crs ); 469 470 GeoTransform sourceGT = new WorldToScreenTransform( sourceBBOX.getMin().getX(), 471 sourceBBOX.getMin().getY(), 472 sourceBBOX.getMax().getX(), 473 sourceBBOX.getMax().getY(), 0, 0, 474 img.getWidth() - 1, img.getHeight() - 1 ); 475 GeoTransform targetGT = new WorldToScreenTransform( targetBBOX.getMin().getX(), 476 targetBBOX.getMin().getY(), 477 targetBBOX.getMax().getX(), 478 targetBBOX.getMax().getY(), 0, 0, 479 img.getWidth() - 1, img.getHeight() - 1 ); 480 481 // create/calculate reference points 482 float dx = img.getWidth() / (float) ( refPointsGridSize - 1 ); 483 float dy = img.getHeight() / (float) ( refPointsGridSize - 1 ); 484 float[] srcCoords = new float[refPointsGridSize * refPointsGridSize * 2]; 485 float[] targetCoords = new float[refPointsGridSize * refPointsGridSize * 2]; 486 int k = 0; 487 for ( int i = 0; i < refPointsGridSize; i++ ) { 488 for ( int j = 0; j < refPointsGridSize; j++ ) { 489 srcCoords[k] = i * dx; 490 srcCoords[k + 1] = j * dy; 491 double x = sourceGT.getSourceX( srcCoords[k] ); 492 double y = sourceGT.getSourceY( srcCoords[k + 1] ); 493 Point point = GeometryFactory.createPoint( x, y, crs ); 494 point = (Point) transform( point ); 495 targetCoords[k] = (float) targetGT.getDestX( point.getX() ); 496 targetCoords[k + 1] = (float) targetGT.getDestY( point.getY() ); 497 k += 2; 498 } 499 } 500 501 // create warp object from reference points and desired interpolation 502 WarpPolynomial warp = WarpPolynomial.createWarp( srcCoords, 0, targetCoords, 0, 503 srcCoords.length, 1f, 1f, 1f, 1f, degree ); 504 505 if ( interpolation == null ) { 506 interpolation = new InterpolationNearest(); 507 } 508 509 // Create and perform the warp operation. 510 ParameterBlock pb = new ParameterBlock(); 511 pb.addSource( img ); 512 pb.add( warp ); 513 pb.add( interpolation ); 514 515 img = JAI.create( "warp", pb ).getAsBufferedImage(); 516 517 // create a new GridCoverage from the warp result. 518 // because warping only can be performed on images the 519 // resulting GridCoverage will be an instance of ImageGridCoverage 520 CoverageOffering oldCO = coverage.getCoverageOffering(); 521 CoverageOffering coverageOffering = null; 522 if ( oldCO != null ) { 523 try { 524 DomainSet ds = oldCO.getDomainSet(); 525 ds.getSpatialDomain().setEnvelops( new Envelope[] { targetBBOX } ); 526 coverageOffering = new CoverageOffering( oldCO.getName(), oldCO.getLabel(), 527 oldCO.getDescription(), 528 oldCO.getMetadataLink(), 529 oldCO.getLonLatEnvelope(), 530 oldCO.getKeywords(), ds, 531 oldCO.getRangeSet(), 532 oldCO.getSupportedCRSs(), 533 oldCO.getSupportedFormats(), 534 oldCO.getSupportedInterpolations(), 535 oldCO.getExtension() ); 536 } catch ( Exception e ) { 537 String s = Messages.getMessage( "CRS_CO_CREATION_ERROR", e.getMessage() ); 538 throw new CRSTransformationException( s ); 539 } 540 } 541 return new ImageGridCoverage( coverageOffering, sourceBBOX, img ); 542 } 543 544 }