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 }