001    //$HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/base/branches/2.5_testing/src/org/deegree/model/spatialschema/JTSAdapter.java $
002    /*----------------------------------------------------------------------------
003     This file is part of deegree, http://deegree.org/
004     Copyright (C) 2001-2009 by:
005     Department of Geography, University of Bonn
006     and
007     lat/lon GmbH
008    
009     This library is free software; you can redistribute it and/or modify it under
010     the terms of the GNU Lesser General Public License as published by the Free
011     Software Foundation; either version 2.1 of the License, or (at your option)
012     any later version.
013     This library is distributed in the hope that it will be useful, but WITHOUT
014     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
015     FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
016     details.
017     You should have received a copy of the GNU Lesser General Public License
018     along with this library; if not, write to the Free Software Foundation, Inc.,
019     59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020    
021     Contact information:
022    
023     lat/lon GmbH
024     Aennchenstr. 19, 53177 Bonn
025     Germany
026     http://lat-lon.de/
027    
028     Department of Geography, University of Bonn
029     Prof. Dr. Klaus Greve
030     Postfach 1147, 53001 Bonn
031     Germany
032     http://www.geographie.uni-bonn.de/deegree/
033    
034     e-mail: info@deegree.org
035     ----------------------------------------------------------------------------*/
036    package org.deegree.model.spatialschema;
037    
038    import org.deegree.framework.log.ILogger;
039    import org.deegree.framework.log.LoggerFactory;
040    
041    import com.vividsolutions.jts.geom.LinearRing;
042    import com.vividsolutions.jts.geom.PrecisionModel;
043    
044    /**
045     * Adapter between deegree <code>Geometry</code>s and JTS <code>Geometry<code> objects.
046     * <p>
047     * Please note that the generated deegree-objects use null as
048     * coordinate system!
049     * 
050     * @author <a href="mailto:mschneider@lat-lon.de">Markus Schneider</a>
051     * @author last edited by: $Author: mschneider $
052     * 
053     * @version $Revision: 19906 $ $Date: 2009-10-01 16:31:29 +0200 (Do, 01 Okt 2009) $
054     */
055    public class JTSAdapter {
056    
057        private static final ILogger LOG = LoggerFactory.getLogger( JTSAdapter.class );
058    
059        // precision model that is used for all JTS geometries
060        private static PrecisionModel pm = new PrecisionModel();
061    
062        // factory for creating JTS geometries
063        private static com.vividsolutions.jts.geom.GeometryFactory jtsFactory = new com.vividsolutions.jts.geom.GeometryFactory(
064                                                                                                                                 pm,
065                                                                                                                                 0 );
066    
067        /**
068         * Converts a deegree <code>Geometry</code> to a corresponding JTS <code>Geometry</code> object.
069         * <p>
070         * Currently, the following conversions are supported:
071         * <ul>
072         * <li>Curve -> LineString</li>
073         * <li>Point -> Point</li>
074         * <li>Surface -> Polygon</li>
075         * <li>MultiCurve -> MultiLineString</li>
076         * <li>MultiPoint -> MultiPoint</li>
077         * <li>MultiSurface -> MultiPolygon</li>
078         * <li>MultiPrimitive -> GeometryCollection</li>
079         * <li>MultiGeometry -> GeometryCollection</li>
080         * </ul>
081         * <p>
082         * 
083         * @param gmObject
084         *            the object to be converted
085         * @return the corresponding JTS-<code>Geometry</code> object
086         * @throws GeometryException
087         *             if type unsupported or conversion failed
088         */
089        public static synchronized com.vividsolutions.jts.geom.Geometry export( Geometry gmObject )
090                                throws GeometryException {
091    
092            com.vividsolutions.jts.geom.Geometry geometry = null;
093            if ( gmObject instanceof Curve ) {
094                geometry = export( (Curve) gmObject );
095            } else if ( gmObject instanceof Point ) {
096                geometry = export( (Point) gmObject );
097            } else if ( gmObject instanceof Surface ) {
098                geometry = export( (Surface) gmObject );
099            } else if ( gmObject instanceof MultiCurve ) {
100                geometry = export( (MultiCurve) gmObject );
101            } else if ( gmObject instanceof MultiPoint ) {
102                geometry = export( (MultiPoint) gmObject );
103            } else if ( gmObject instanceof MultiSurface ) {
104                geometry = export( (MultiSurface) gmObject );
105            } else if ( gmObject instanceof MultiPrimitive ) {
106                geometry = export( (MultiPrimitive) gmObject );
107            } else if ( gmObject instanceof MultiGeometry ) {
108                geometry = export( (MultiGeometry) gmObject );
109            } else {
110                throw new GeometryException( "JTSAdapter.export does not support type '" + gmObject.getClass().getName()
111                                             + "'!" );
112            }
113            return geometry;
114        }
115    
116        /**
117         * Converts a JTS <code>Geometry</code> object to a corresponding deegree <code>Geometry</code>.
118         * <p>
119         * Currently, the following conversions are supported:
120         * <ul>
121         * <li>LineString -> Curve
122         * <li>Point -> Point
123         * <li>Polygon -> Surface
124         * <li>MultiLineString -> MultiCurve
125         * <li>MultiPoint -> MultiPoint
126         * <li>MultiPolygon -> MultiSurface
127         * <li>GeometryCollection -> MultiGeometry
128         * </ul>
129         * <p>
130         * 
131         * @param geometry
132         *            the JTS-<code>Geometry</code> to be converted
133         * @return the corresponding <code>Geometry</code>
134         * @throws GeometryException
135         *             if type unsupported or conversion failed
136         */
137        public static Geometry wrap( com.vividsolutions.jts.geom.Geometry geometry )
138                                throws GeometryException {
139    
140            Geometry gmObject = null;
141            if ( geometry instanceof com.vividsolutions.jts.geom.LineString ) {
142                gmObject = wrap( (com.vividsolutions.jts.geom.LineString) geometry );
143            } else if ( geometry instanceof com.vividsolutions.jts.geom.Point ) {
144                gmObject = wrap( (com.vividsolutions.jts.geom.Point) geometry );
145            } else if ( geometry instanceof com.vividsolutions.jts.geom.Polygon ) {
146                gmObject = wrap( (com.vividsolutions.jts.geom.Polygon) geometry );
147            } else if ( geometry instanceof com.vividsolutions.jts.geom.MultiLineString ) {
148                gmObject = wrap( (com.vividsolutions.jts.geom.MultiLineString) geometry );
149            } else if ( geometry instanceof com.vividsolutions.jts.geom.MultiPoint ) {
150                gmObject = wrap( (com.vividsolutions.jts.geom.MultiPoint) geometry );
151            } else if ( geometry instanceof com.vividsolutions.jts.geom.MultiPolygon ) {
152                gmObject = wrap( (com.vividsolutions.jts.geom.MultiPolygon) geometry );
153            } else if ( geometry instanceof com.vividsolutions.jts.geom.GeometryCollection ) {
154                gmObject = wrap( (com.vividsolutions.jts.geom.GeometryCollection) geometry );
155            } else {
156                throw new GeometryException( "JTSAdapter.wrap does not support type '" + geometry.getClass().getName()
157                                             + "'!" );
158            }
159            return gmObject;
160        }
161    
162        /**
163         * Converts a deegree <code>Point</code> to a JTS <code>Point</code>.
164         * 
165         * @param gmPoint
166         *            point to be converted
167         * @return the corresponding <code>Point</code> object
168         */
169        private static synchronized com.vividsolutions.jts.geom.Point export( Point gmPoint ) {
170    
171            com.vividsolutions.jts.geom.Coordinate coord = new com.vividsolutions.jts.geom.Coordinate( gmPoint.getX(),
172                                                                                                       gmPoint.getY() );
173    
174            return jtsFactory.createPoint( coord );
175        }
176    
177        /**
178         * Converts a deegree <code>MultiPoint</code> to a JTS <code>MultiPoint</code>.
179         * 
180         * @param gmMultiPoint
181         *            multipoint to be converted
182         * @return the corresponding <code>MultiPoint</code> object
183         */
184        private static synchronized com.vividsolutions.jts.geom.MultiPoint export( MultiPoint gmMultiPoint ) {
185            Point[] gmPoints = gmMultiPoint.getAllPoints();
186            com.vividsolutions.jts.geom.Point[] points = new com.vividsolutions.jts.geom.Point[gmPoints.length];
187            for ( int i = 0; i < points.length; i++ ) {
188                points[i] = export( gmPoints[i] );
189            }
190            return jtsFactory.createMultiPoint( points );
191        }
192    
193        /**
194         * Converts a deegree <code>Curve</code> to a JTS <code>LineString</code>.
195         * 
196         * @param curve
197         *            <code>Curve</code> to be converted
198         * @return the corresponding <code>LineString</code> object
199         * @throws GeometryException
200         */
201        private static synchronized com.vividsolutions.jts.geom.LineString export( Curve curve )
202                                throws GeometryException {
203    
204            LineString lineString = curve.getAsLineString();
205            com.vividsolutions.jts.geom.Coordinate[] coords = new com.vividsolutions.jts.geom.Coordinate[lineString.getNumberOfPoints()];
206            for ( int i = 0; i < coords.length; i++ ) {
207                Position position = lineString.getPositionAt( i );
208                coords[i] = new com.vividsolutions.jts.geom.Coordinate( position.getX(), position.getY() );
209            }
210            return jtsFactory.createLineString( coords );
211        }
212    
213        /**
214         * Converts a deegree <code>MultiCurve</code> to a JTS <code>MultiLineString</code>.
215         * 
216         * @param multi
217         *            <code>MultiCurve</code> to be converted
218         * @return the corresponding <code>MultiLineString</code> object
219         * @throws GeometryException
220         */
221        private static synchronized com.vividsolutions.jts.geom.MultiLineString export( MultiCurve multi )
222                                throws GeometryException {
223    
224            Curve[] curves = multi.getAllCurves();
225            com.vividsolutions.jts.geom.LineString[] lineStrings = new com.vividsolutions.jts.geom.LineString[curves.length];
226            for ( int i = 0; i < curves.length; i++ ) {
227                lineStrings[i] = export( curves[i] );
228            }
229            return jtsFactory.createMultiLineString( lineStrings );
230        }
231    
232        /**
233         * Converts an array of deegree <code>Position</code>s to a JTS <code>LinearRing</code>.
234         * 
235         * @param positions
236         *            an array of <code>Position</code>s
237         * @return the corresponding <code>LinearRing</code> object
238         */
239        public static synchronized com.vividsolutions.jts.geom.LinearRing export( Position[] positions ) {
240            com.vividsolutions.jts.geom.Coordinate[] coords = new com.vividsolutions.jts.geom.Coordinate[positions.length];
241            for ( int i = 0; i < positions.length; i++ ) {
242                coords[i] = new com.vividsolutions.jts.geom.Coordinate( positions[i].getX(), positions[i].getY() );
243            }
244            return jtsFactory.createLinearRing( coords );
245        }
246    
247        /**
248         * Converts a deegree <code>SurfacePatch</code> into a JTS <code>Polygon</code>.
249         * 
250         * @param patch
251         *            {@link SurfacePatch}
252         * @return corresponding JTS <code>Polygon</code> object
253         */
254        public static synchronized com.vividsolutions.jts.geom.Polygon export( SurfacePatch patch ) {
255    
256            // convert exterior ring
257            LinearRing jtsShell = export( patch.getExteriorRing() );
258    
259            // convert interior rings
260            LinearRing[] jtsHoles = null;
261            Ring[] interiorRings = patch.getInterior();
262            if ( interiorRings != null ) {
263                jtsHoles = new LinearRing[interiorRings.length];
264                for ( int i = 0; i < interiorRings.length; i++ ) {
265                    jtsHoles[i] = export( interiorRings[i].getPositions() );
266                }
267            }
268            return jtsFactory.createPolygon( jtsShell, jtsHoles );
269        }
270    
271        /**
272         * Converts a deegree <code>Surface</code> to a JTS <code>Polygon</code>.
273         * <p>
274         * Currently, the <code>Surface</code> _must_ contain exactly one patch!
275         * 
276         * @param surface
277         *            a <code>Surface</code>
278         * @return the corresponding <code>Polygon</code> object
279         */
280        private static synchronized com.vividsolutions.jts.geom.Polygon export( Surface surface ) {
281            SurfacePatch patch = null;
282            try {
283                patch = surface.getSurfacePatchAt( 0 );
284                Position[] exteriorRing = patch.getExteriorRing();
285                Position[][] interiorRings = patch.getInteriorRings();
286    
287                com.vividsolutions.jts.geom.LinearRing shell = export( exteriorRing );
288                com.vividsolutions.jts.geom.LinearRing[] holes = new com.vividsolutions.jts.geom.LinearRing[0];
289                if ( interiorRings != null ) {
290                    holes = new com.vividsolutions.jts.geom.LinearRing[interiorRings.length];
291                    for ( int i = 0; i < holes.length; i++ ) {
292                        holes[i] = export( interiorRings[i] );
293                    }
294                }
295                return jtsFactory.createPolygon( shell, holes );
296            } catch ( GeometryException e ) {
297                LOG.logError( "", e );
298            }
299            return null;
300        }
301    
302        /**
303         * Converts a JTS <code>MultiSurface</code> to a deegree <code>MultiPolygon</code>.
304         * <p>
305         * Currently, the contained <code>Surface</code> _must_ have exactly one patch!
306         * 
307         * @param msurface
308         *            a <code>MultiSurface</code>
309         * @return the corresponding <code>MultiPolygon</code> object
310         */
311        private static synchronized com.vividsolutions.jts.geom.MultiPolygon export( MultiSurface msurface ) {
312    
313            Surface[] surfaces = msurface.getAllSurfaces();
314            com.vividsolutions.jts.geom.Polygon[] polygons = new com.vividsolutions.jts.geom.Polygon[surfaces.length];
315    
316            for ( int i = 0; i < surfaces.length; i++ ) {
317                polygons[i] = export( surfaces[i] );
318            }
319            return jtsFactory.createMultiPolygon( polygons );
320        }
321    
322        /**
323         * Converts a JTS <code>MultiPrimitive</code> to a deegree <code>GeometryCollection</code>.
324         * 
325         * @param multi
326         *            a <code>MultiPrimitive</code>
327         * @return the corresponding <code>GeometryCollection</code> object
328         * @throws GeometryException
329         */
330        private static synchronized com.vividsolutions.jts.geom.GeometryCollection export( MultiPrimitive multi )
331                                throws GeometryException {
332    
333            Geometry[] primitives = multi.getAllPrimitives();
334            com.vividsolutions.jts.geom.Geometry[] geometries = new com.vividsolutions.jts.geom.Geometry[primitives.length];
335    
336            for ( int i = 0; i < primitives.length; i++ ) {
337                geometries[i] = export( primitives[i] );
338            }
339            return jtsFactory.createGeometryCollection( geometries );
340        }
341    
342        /**
343         * Converts a JTS <code>MultiGeometry</code> into a deegree <code>GeometryCollection</code>.
344         * 
345         * @param multi
346         *            a <code>MultiGeometry</code>
347         * @return corresponding <code>GeometryCollection</code> object
348         * @throws GeometryException
349         */
350        private static synchronized com.vividsolutions.jts.geom.GeometryCollection export( MultiGeometry multi )
351                                throws GeometryException {
352    
353            Geometry[] memberGeometries = multi.getAll();
354            com.vividsolutions.jts.geom.Geometry[] jtsMemberGeometries = new com.vividsolutions.jts.geom.Geometry[memberGeometries.length];
355            for ( int i = 0; i < memberGeometries.length; i++ ) {
356                jtsMemberGeometries[i] = export( memberGeometries[i] );
357            }
358            return jtsFactory.createGeometryCollection( jtsMemberGeometries );
359        }
360    
361        /**
362         * Converts a JTS <code>Point</code> to a deegree <code>Point</code>.
363         * 
364         * @param point
365         *            a <code>Point</code> object
366         * @return the corresponding <code>Point</code>
367         */
368        private static Point wrap( com.vividsolutions.jts.geom.Point point ) {
369            com.vividsolutions.jts.geom.Coordinate coord = point.getCoordinate();
370            return Double.isNaN( coord.z ) ? new PointImpl( coord.x, coord.y, null ) : new PointImpl( coord.x, coord.y,
371                                                                                                      coord.z, null );
372        }
373    
374        /**
375         * Converts a JTS <code>MultiPoint</code> to a deegree <code>MultiPoint</code>.
376         * 
377         * @param multi
378         *            a <code>MultiPoint</code> object
379         * @return the corresponding <code>MultiPoint</code>
380         */
381        private static MultiPoint wrap( com.vividsolutions.jts.geom.MultiPoint multi ) {
382            Point[] gmPoints = new Point[multi.getNumGeometries()];
383            for ( int i = 0; i < gmPoints.length; i++ ) {
384                gmPoints[i] = wrap( (com.vividsolutions.jts.geom.Point) multi.getGeometryN( i ) );
385            }
386            return new MultiPointImpl( gmPoints, null );
387        }
388    
389        /**
390         * Converts a <code>LineString</code> to a <code>Curve</code>.
391         * 
392         * @param line
393         *            a <code>LineString</code> object
394         * @return the corresponding <code>Curve</code>
395         * @throws GeometryException
396         */
397        private static Curve wrap( com.vividsolutions.jts.geom.LineString line )
398                                throws GeometryException {
399            com.vividsolutions.jts.geom.Coordinate[] coords = line.getCoordinates();
400            Position[] positions = new Position[coords.length];
401            for ( int i = 0; i < coords.length; i++ ) {
402                positions[i] = new PositionImpl( coords[i].x, coords[i].y );
403            }
404            return GeometryFactory.createCurve( positions, null );
405        }
406    
407        /**
408         * Converts a <code>MultiLineString</code> to a <code>MultiCurve</code>.
409         * 
410         * @param multi
411         *            a <code>MultiLineString</code> object
412         * @return the corresponding <code>MultiCurve</code>
413         * @throws GeometryException
414         */
415        private static MultiCurve wrap( com.vividsolutions.jts.geom.MultiLineString multi )
416                                throws GeometryException {
417            Curve[] curves = new Curve[multi.getNumGeometries()];
418            for ( int i = 0; i < curves.length; i++ ) {
419                curves[i] = wrap( (com.vividsolutions.jts.geom.LineString) multi.getGeometryN( i ) );
420            }
421            return GeometryFactory.createMultiCurve( curves );
422        }
423    
424        /**
425         * Converts a <code>Polygon</code> to a <code>Surface</code>.
426         * 
427         * @param polygon
428         *            a <code>Polygon</code>
429         * @return the corresponding <code>Surface</code> object
430         * @throws GeometryException
431         */
432        private static Surface wrap( com.vividsolutions.jts.geom.Polygon polygon )
433                                throws GeometryException {
434    
435            Position[] exteriorRing = createGMPositions( polygon.getExteriorRing() );
436            Position[][] interiorRings = new Position[polygon.getNumInteriorRing()][];
437    
438            for ( int i = 0; i < interiorRings.length; i++ ) {
439                interiorRings[i] = createGMPositions( polygon.getInteriorRingN( i ) );
440            }
441            SurfacePatch patch = new PolygonImpl( new SurfaceInterpolationImpl(), exteriorRing, interiorRings, null );
442    
443            return new SurfaceImpl( patch );
444        }
445    
446        /**
447         * Converts a <code>MultiPolygon</code> to a <code>MultiSurface</code>.
448         * 
449         * @param multiPolygon
450         *            a <code>MultiPolygon</code>
451         * @return the corresponding <code>MultiSurface</code> object
452         * @throws GeometryException
453         */
454        private static MultiSurface wrap( com.vividsolutions.jts.geom.MultiPolygon multiPolygon )
455                                throws GeometryException {
456    
457            Surface[] surfaces = new Surface[multiPolygon.getNumGeometries()];
458            for ( int i = 0; i < surfaces.length; i++ ) {
459                surfaces[i] = wrap( (com.vividsolutions.jts.geom.Polygon) multiPolygon.getGeometryN( i ) );
460            }
461            return new MultiSurfaceImpl( surfaces );
462        }
463    
464        /**
465         * Converts a <code>GeometryCollection</code> to a <code>MultiGeometry</code>.
466         * 
467         * @param collection
468         *            a <code>GeometryCollection</code>
469         * @return the corresponding <code>MultiGeometry</code> object
470         * @throws GeometryException
471         */
472        private static MultiGeometry wrap( com.vividsolutions.jts.geom.GeometryCollection collection )
473                                throws GeometryException {
474    
475            MultiGeometry multi = new MultiGeometryImpl( null );
476            for ( int i = 0; i < collection.getNumGeometries(); i++ ) {
477                multi.add( wrap( collection.getGeometryN( i ) ) );
478            }
479            return multi;
480        }
481    
482        /**
483         * Converts a <code>LineString</code> to an array of <code>Position</code>s.
484         * 
485         * @param line
486         *            a <code>LineString</code> object
487         * @return the corresponding array of <code>Position</code>s
488         */
489        private static Position[] createGMPositions( com.vividsolutions.jts.geom.LineString line ) {
490            com.vividsolutions.jts.geom.Coordinate[] coords = line.getCoordinates();
491            Position[] positions = new Position[coords.length];
492            for ( int i = 0; i < coords.length; i++ ) {
493                positions[i] = new PositionImpl( coords[i].x, coords[i].y );
494            }
495            return positions;
496        }
497    }