001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/io/datastore/sql/postgis/PGgeometryAdapter.java $
002    /*----------------    FILE HEADER  ------------------------------------------
003     This file is part of deegree.
004     Copyright (C) 2001-2006 by:
005     Department of Geography, University of Bonn
006     http://www.giub.uni-bonn.de/deegree/
007     lat/lon GmbH
008     http://www.lat-lon.de
009    
010     This library is free software; you can redistribute it and/or
011     modify it under the terms of the GNU Lesser General Public
012     License as published by the Free Software Foundation; either
013     version 2.1 of the License, or (at your option) any later version.
014    
015     This library is distributed in the hope that it will be useful,
016     but WITHOUT ANY WARRANTY; without even the implied warranty of
017     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
018     Lesser General Public License for more details.
019    
020     You should have received a copy of the GNU Lesser General Public
021     License along with this library; if not, write to the Free Software
022     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
023    
024     Contact:
025    
026     Andreas Poth
027     lat/lon GmbH
028     Aennchenstraße 19
029     53177 Bonn
030     Germany
031     E-Mail: poth@lat-lon.de
032    
033     Jens Fitzke
034     lat/lon GmbH
035     Aennchenstraße 19
036     53177 Bonn
037     Germany
038     E-Mail: jens.fitzke@uni-bonn.de
039     ---------------------------------------------------------------------------*/
040    
041    package org.deegree.io.datastore.sql.postgis;
042    
043    import java.sql.SQLException;
044    
045    import org.deegree.model.crs.CoordinateSystem;
046    import org.deegree.model.spatialschema.Curve;
047    import org.deegree.model.spatialschema.Envelope;
048    import org.deegree.model.spatialschema.Geometry;
049    import org.deegree.model.spatialschema.GeometryException;
050    import org.deegree.model.spatialschema.GeometryFactory;
051    import org.deegree.model.spatialschema.MultiCurve;
052    import org.deegree.model.spatialschema.MultiPoint;
053    import org.deegree.model.spatialschema.MultiSurface;
054    import org.deegree.model.spatialschema.Point;
055    import org.deegree.model.spatialschema.Position;
056    import org.deegree.model.spatialschema.Surface;
057    import org.deegree.model.spatialschema.SurfaceInterpolationImpl;
058    import org.deegree.model.spatialschema.WKTAdapter;
059    import org.postgis.LineString;
060    import org.postgis.MultiLineString;
061    import org.postgis.MultiPolygon;
062    import org.postgis.PGbox3d;
063    import org.postgis.PGboxbase;
064    import org.postgis.PGgeometry;
065    import org.postgis.Polygon;
066    
067    /**
068     * Adapter between deegree <code>Geometry</code> objects and PostGIS <code>Geometry</code>
069     * objects.
070     * 
071     * @author <a href="mailto:schneider@lat-lon.de">Markus Schneider </A>
072     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth </a>
073     * 
074     * @author last edited by: $Author: mschneider $
075     * 
076     * @version $Revision: 6588 $, $Date: 2007-04-11 17:31:29 +0200 (Mi, 11 Apr 2007) $
077     */
078    public class PGgeometryAdapter {
079    
080        private PGgeometryAdapter() {
081            // avoid instantiation
082        }
083    
084        /**
085         * Converts a deegree <code>Geometry</code> instance to a corresponding PostGIS
086         * {@link PGgeometry} object.
087         * 
088         * @param geometry
089         *            deegree <code>Geometry</code> to be converted
090         * @param srid
091         *            PostGIS SRS id that is used to store the geometry
092         * @return corresponding PostGIS <code>Geometry</code>
093         * @throws GeometryException
094         */
095        public static PGgeometry export( Geometry geometry, int srid )
096                                throws GeometryException {
097            PGgeometry pgGeometry = null;
098            if ( geometry instanceof Point ) {
099                pgGeometry = exportPoint( (Point) geometry, srid );
100            } else if ( geometry instanceof MultiPoint ) {
101                pgGeometry = exportMultiPoint( (MultiPoint) geometry, srid );
102            } else if ( geometry instanceof Curve ) {
103                pgGeometry = exportCurve( (Curve) geometry, srid );
104            } else if ( geometry instanceof MultiCurve ) {
105                pgGeometry = exportMultiCurve( (MultiCurve) geometry, srid );
106            } else if ( geometry instanceof Surface ) {
107                pgGeometry = exportSurface( (Surface) geometry, srid );
108            } else if ( geometry instanceof MultiSurface ) {
109                pgGeometry = exportMultiSurface( (MultiSurface) geometry, srid );
110            } else {
111                throw new GeometryException( "Cannot export geometry of type '" + geometry.getClass()
112                                             + "' to PostGIS geometry: Unsupported type." );
113            }
114            return pgGeometry;
115        }
116    
117        /**
118         * Converts a deegree <code>Envelope</code> instance to a corresponding PostGIS
119         * <code>PGboxbase</code> object.
120         * 
121         * @param envelope
122         *            deegree <code>Envelope</code> to be converted
123         * @return corresponding PostGIS <code>PGboxbase</code>
124         * @throws GeometryException
125         */
126        public static PGboxbase export( Envelope envelope )
127                                throws GeometryException {
128            StringBuffer sb = WKTAdapter.export( envelope );
129            PGbox3d box = null;
130            try {
131                box = new PGbox3d( sb.toString() );
132            } catch ( Exception e ) {
133                throw new GeometryException( e.toString() );
134            }
135    
136            return box;
137        }
138    
139        /**
140         * Converts a PostGIS <code>Geometry</code> instance to a corresponding deegree
141         * <code>Geometry</code> object.
142         * 
143         * @param pgGeometry
144         *            PostGIS <code>PGgeometry</code> to be converted
145         * @param crs
146         *            coordinate system of the created deegree <code>Geometry</code> object
147         * @return corresponding deegree <code>Geometry</code>
148         * @throws GeometryException
149         */
150        public static Geometry wrap( PGgeometry pgGeometry, CoordinateSystem crs )
151                                throws GeometryException {
152            Geometry geo = null;
153    
154            switch ( pgGeometry.getGeoType() ) {
155            case org.postgis.Geometry.POINT:
156                geo = wrapPoint( (org.postgis.Point) pgGeometry.getGeometry(), crs );
157                break;
158            case org.postgis.Geometry.LINESTRING:
159                geo = wrapCurve( (LineString) pgGeometry.getGeometry(), crs );
160                break;
161            case org.postgis.Geometry.POLYGON:
162                geo = wrapSurface( (Polygon) pgGeometry.getGeometry(), crs );
163                break;
164            case org.postgis.Geometry.MULTIPOINT:
165                geo = wrapMultiPoint( (org.postgis.MultiPoint) pgGeometry.getGeometry(), crs );
166                break;
167            case org.postgis.Geometry.MULTILINESTRING:
168                geo = wrapMultiCurve( (MultiLineString) pgGeometry.getGeometry(), crs );
169                break;
170            case org.postgis.Geometry.MULTIPOLYGON:
171                geo = wrapMultiSurface( (MultiPolygon) pgGeometry.getGeometry(), crs );
172                break;
173            case org.postgis.Geometry.GEOMETRYCOLLECTION:
174            default: {
175                throw new GeometryException( "Cannot export PostGIS geometry of type '" + pgGeometry.getType()
176                                             + "' to deegree geometry: Unsupported type." );
177            }
178            }
179            return geo;
180        }
181    
182        /**
183         * Creates a PostGIS <code>MultiPoint</code> from a deegree <code>Point</code>.
184         * 
185         * @param point
186         * @param srid
187         *            PostGIS SRS id that is used to store the geometry
188         * @throws GeometryException
189         */
190        private static PGgeometry exportPoint( Point point, int srid )
191                                throws GeometryException {
192    
193            StringBuffer sb = WKTAdapter.export( point );
194            org.postgis.Point pgPoint = null;
195    
196            try {
197                pgPoint = new org.postgis.Point( sb.toString() );
198            } catch ( SQLException e ) {
199                throw new GeometryException( e.toString() );
200            }
201    
202            pgPoint.setSrid( srid );
203            return new PGgeometry( pgPoint );
204        }
205    
206        /**
207         * Creates a PostGIS <code>MultiPoint</code> from a deegree <code>MultiPoint</code>.
208         * 
209         * @param multiPoint
210         * @param srid
211         *            PostGIS SRS id that is used to store the geometry
212         * @throws GeometryException
213         */
214        private static PGgeometry exportMultiPoint( MultiPoint multiPoint, int srid )
215                                throws GeometryException {
216    
217            StringBuffer sb = WKTAdapter.export( multiPoint );
218            org.postgis.MultiPoint pgMPoint = null;
219    
220            try {
221                pgMPoint = new org.postgis.MultiPoint( sb.toString() );
222            } catch ( Exception e ) {
223                throw new GeometryException( e.toString() );
224            }
225    
226            pgMPoint.setSrid( srid );
227            return new PGgeometry( pgMPoint );
228        }
229    
230        /**
231         * Creates a PostGIS <code>LineString</code> from a deegree <code>Curve</code>.
232         * 
233         * @param curve
234         * @param srid
235         *            PostGIS SRS id that is used to store the geometry
236         */
237        private static PGgeometry exportCurve( Curve curve, int srid )
238                                throws GeometryException {
239            StringBuffer sb = WKTAdapter.export( curve );
240            org.postgis.LineString pgLineString = null;
241    
242            try {
243                pgLineString = new org.postgis.LineString( sb.toString() );
244            } catch ( Exception e ) {
245                throw new GeometryException( e.toString() );
246            }
247    
248            pgLineString.setSrid( srid );
249            return new PGgeometry( pgLineString );
250        }
251    
252        /**
253         * Creates a PostGIS <code>org.postgis.MultiCurve</code> from a deegree
254         * <code>MultiCurve</code>.
255         * 
256         * @param multiCurve
257         * @param srid
258         *            PostGIS SRS id that is used to store the geometry
259         * @throws GeometryException
260         */
261        private static PGgeometry exportMultiCurve( MultiCurve multiCurve, int srid )
262                                throws GeometryException {
263            StringBuffer sb = WKTAdapter.export( multiCurve );
264            org.postgis.MultiLineString pgMLineString = null;
265    
266            try {
267                pgMLineString = new org.postgis.MultiLineString( sb.toString() );
268            } catch ( Exception e ) {
269                throw new GeometryException( e.toString() );
270            }
271    
272            pgMLineString.setSrid( srid );
273            return new PGgeometry( pgMLineString );
274        }
275    
276        /**
277         * Creates a PostGIS <code>Polygon</code> from a deegree <code>Surface</code>.
278         * 
279         * @param surface
280         * @param srid
281         *            PostGIS SRS id that is used to store the geometry
282         * @throws GeometryException
283         */
284        private static PGgeometry exportSurface( Surface surface, int srid )
285                                throws GeometryException {
286            StringBuffer sb = WKTAdapter.export( surface );
287            org.postgis.Polygon pgPoly = null;
288    
289            try {
290                pgPoly = new org.postgis.Polygon( sb.toString() );
291            } catch ( Exception e ) {
292                throw new GeometryException( e.toString() );
293            }
294    
295            pgPoly.setSrid( srid );
296            return new PGgeometry( pgPoly );
297        }
298    
299        /**
300         * Creates a PostGIS <code>MultiPolygon</code> from a deegree <code>MultiSurface</code>.
301         * 
302         * @param multiSurface
303         * @param srid
304         *            PostGIS SRS id that is used to store the geometry
305         * @throws GeometryException
306         */
307        private static PGgeometry exportMultiSurface( MultiSurface multiSurface, int srid )
308                                throws GeometryException {
309            StringBuffer sb = WKTAdapter.export( multiSurface );
310            org.postgis.MultiPolygon pgMPoly = null;
311    
312            try {
313                pgMPoly = new org.postgis.MultiPolygon( sb.toString() );
314            } catch ( Exception e ) {
315                throw new GeometryException( e.toString() );
316            }
317    
318            pgMPoly.setSrid( srid );
319            return new PGgeometry( pgMPoly );
320        }
321    
322        /**
323         * Creates a deegree <code>Point</code> from a PostGIS <code>Point</code>.
324         * 
325         * @param pgPoint
326         *            PostGIS <code>Point</code>
327         * @param crs
328         *            coordinate system of the created deegree <code>Geometry</code> object
329         * @return deegree <code>Point</code>
330         */
331        private static Point wrapPoint( org.postgis.Point pgPoint, CoordinateSystem crs ) {
332            // if geometry is 2-dimensional
333            Position p = null;
334            if ( pgPoint.getDimension() == 2 ) {
335                // convert PostGIS Point to a Point using the GeometryFactory
336                p = GeometryFactory.createPosition( new double[] { pgPoint.getX(), pgPoint.getY() } );
337                // if geometry is 3-dimensional
338            } else if ( pgPoint.getDimension() == 3 ) {
339                // convert PostGIS Point to a Point using the GeometryFactory
340                p = GeometryFactory.createPosition( new double[] { pgPoint.getX(), pgPoint.getY(), pgPoint.getZ() } );
341            }
342            return GeometryFactory.createPoint( p, crs );
343        }
344    
345        /**
346         * Creates a deegree <code>MultiPoint</code> from a PostGIS <code>MultiPoint</code>.
347         * 
348         * @param pgMultiPoint
349         *            PostGIS <code>MultiPoint</code>
350         * @param crs
351         *            coordinate system of the created deegree <code>Geometry</code> object
352         * @return deegree <code>MultiPoint</code>
353         * @throws GeometryException
354         * 
355         */
356        private static MultiPoint wrapMultiPoint( org.postgis.MultiPoint pgMultiPoint, CoordinateSystem crs ) {
357            // create a temporary Point Array to store the Points the
358            // MultiPoint will consist of
359            Point[] mpoints = new Point[pgMultiPoint.numPoints()];
360            // for all Points
361            for ( int i = 0; i < pgMultiPoint.numPoints(); i++ ) {
362                // convert PostGIS Point to a Point using the GeometryFactory
363                mpoints[i] = wrapPoint( pgMultiPoint.getPoint( i ), crs );
364            }
365            // create a Multipoint from the Array points
366            return GeometryFactory.createMultiPoint( mpoints );
367        }
368    
369        /**
370         * Creates a deegree <code>Curve</code> from a PostGIS <code>LineString</code>.
371         * 
372         * @param pgLineString
373         *            PostGIS <code>LineString</code>
374         * @param crs
375         *            coordinate system of the created deegree <code>Geometry</code> object
376         * @return deegree <code>Curve</code>
377         * @throws GeometryException
378         */
379        private static Curve wrapCurve( LineString pgLineString, CoordinateSystem crs )
380                                throws GeometryException {
381            // create a Position Array. Used to store the Points the
382            // Curve will consist of
383            Position[] points = new Position[pgLineString.numPoints()];
384    
385            // if geometry is 2-dimensional
386            if ( pgLineString.getDimension() == 2 ) {
387                // for all Points
388                for ( int i = 0; i < pgLineString.numPoints(); i++ ) {
389                    // create a Position from the PostGIS Point using the
390                    // GeometryFactory
391                    double[] d = new double[] { pgLineString.getPoint( i ).getX(), pgLineString.getPoint( i ).getY() };
392                    points[i] = GeometryFactory.createPosition( d );
393                }
394                // if geometry is 3-dimensional
395            } else if ( pgLineString.getDimension() == 3 ) {
396                // for all Points
397                for ( int i = 0; i < pgLineString.numPoints(); i++ ) {
398                    // create a Position from the PostGIS Point using the
399                    // GeometryFactory
400                    double[] d = new double[] { pgLineString.getPoint( i ).getX(), pgLineString.getPoint( i ).getY(),
401                                               pgLineString.getPoint( i ).getZ() };
402                    points[i] = GeometryFactory.createPosition( d );
403                }
404            }
405            return GeometryFactory.createCurve( points, crs );
406        }
407    
408        /**
409         * Creates a deegree <code>MultiCurve</code> from a PostGIS <code>MultiLineString</code>.
410         * 
411         * @param pgMultiLineString
412         *            PostGIS <code>MultiLineString</code>
413         * @param crs
414         *            coordinate system of the created deegree <code>Geometry</code> object
415         * @return deegree <code>MultiCurve</code>
416         * @throws GeometryException
417         */
418        private static MultiCurve wrapMultiCurve( MultiLineString pgMultiLineString, CoordinateSystem crs )
419                                throws GeometryException {
420            // create a Curve Array. Used to store the CurveSegments the
421            // Curve will consist of
422            Curve[] curves = new Curve[pgMultiLineString.numLines()];
423            // for all Lines
424            for ( int i = 0; i < pgMultiLineString.numLines(); i++ ) {
425                // create a Curve form the positions Array using the
426                // GeometryFactory
427                curves[i] = wrapCurve( pgMultiLineString.getLine( i ), crs );
428            }
429            // create a Curve form all the CurveSegments stored in the
430            // csegments Array using the GeometryFactory
431            return GeometryFactory.createMultiCurve( curves );
432        }
433    
434        /**
435         * Creates a deegree <code>Surface</code> from a PostGIS <code>Polygon</code>.
436         * 
437         * @param geometry
438         *            PostGIS <code>Polygon</code>
439         * @param crs
440         *            coordinate system of the created deegree <code>Geometry</code> object
441         * @return deegree <code>Surface</code>
442         * @throws GeometryException
443         */
444        private static Surface wrapSurface( Polygon pgPolygon, CoordinateSystem crs )
445                                throws GeometryException {
446    
447            // create a Position Array. Used to store the Positions the
448            // exterior Ring of the Surface will consist of
449            Position[] eRing = new Position[pgPolygon.getRing( 0 ).numPoints()];
450            // declares a Position[][] Array. Used to store the Positions
451            // of the interior Rings the Surface will consist of. The exterior
452            // Ring is stored seperately
453            Position[][] iRings = null;
454    
455            // if geometry is 2-dimensional
456            if ( pgPolygon.getDimension() == 2 ) {
457                // for all the Points of the fist LinearRing (which is the exterior)
458                org.postgis.LinearRing ring = pgPolygon.getRing( 0 );
459                for ( int j = 0; j < eRing.length; j++ ) {
460                    // store all the Points of the exterior Ring in the Array
461                    // eRing. Convert them using GeometryFactory
462                    double[] d = new double[] { ring.getPoint( j ).getX(), ring.getPoint( j ).getY() };
463                    eRing[j] = GeometryFactory.createPosition( d );
464                }
465    
466                if ( pgPolygon.numRings() > 1 ) {
467                    iRings = new Position[pgPolygon.numRings() - 1][];
468                    // for all LinearRings except the first one (which is the exterior one)
469                    for ( int i = 1; i < pgPolygon.numRings(); i++ ) {
470                        iRings[i - 1] = new Position[pgPolygon.getRing( i ).numPoints()];
471                        // for all the Points in the ith LinearRing
472                        ring = pgPolygon.getRing( i );
473                        for ( int j = 0; j < ring.numPoints(); j++ ) {
474                            // store all the Points of the ith interior Ring in
475                            // the iRings Array
476                            double[] d = new double[] { ring.getPoint( j ).getX(), ring.getPoint( j ).getY() };
477                            iRings[i - 1][j] = GeometryFactory.createPosition( d );
478                        }
479                    }
480                }
481                // if geometry is 3-dimensional
482            } else if ( pgPolygon.getDimension() == 3 ) {
483                // for all the Points of the fist LinearRing (which is the exterior)
484                org.postgis.LinearRing ring = pgPolygon.getRing( 0 );
485                for ( int j = 0; j < ring.numPoints(); j++ ) {
486                    // store all the Points of the exterior Ring in the Array
487                    // eRing. Convert them using GeometryFactory
488                    double[] d = new double[] { ring.getPoint( j ).getX(), ring.getPoint( j ).getY(),
489                                               ring.getPoint( j ).getZ() };
490                    eRing[j] = GeometryFactory.createPosition( d );
491                }
492    
493                if ( pgPolygon.numRings() > 1 ) {
494                    iRings = new Position[pgPolygon.numRings() - 1][];
495                    // for all LinearRings except the first one (which is the exterior one)
496                    for ( int i = 1; i < pgPolygon.numRings(); i++ ) {
497                        iRings[i - 1] = new Position[pgPolygon.getRing( i ).numPoints()];
498                        // for all the Points in the ith LinearRing
499                        ring = pgPolygon.getRing( i );
500                        for ( int j = 0; j < ring.numPoints(); j++ ) {
501                            // store all the Points of the ith interior Ring in the iRings Array
502                            double[] d = new double[] { ring.getPoint( j ).getX(), ring.getPoint( j ).getY(),
503                                                       ring.getPoint( j ).getZ() };
504                            iRings[i - 1][j] = GeometryFactory.createPosition( d );
505                        }
506                    }
507                }
508            }
509    
510            return GeometryFactory.createSurface( eRing, iRings, new SurfaceInterpolationImpl(), crs );
511        }
512    
513        /**
514         * Creates a deegree <code>MultiSurface</code> from a PostGIS <code>MultiPolygon</code>.
515         * 
516         * @param pgMultiPolygon
517         *            PostGIS <code>MultiPolygon</code>
518         * @param crs
519         *            coordinate system of the created deegree <code>Geometry</code> object
520         * @return deegree <code>MultiSurface</code>
521         * @throws GeometryException
522         */
523        private static MultiSurface wrapMultiSurface( MultiPolygon pgMultiPolygon, CoordinateSystem crs )
524                                throws GeometryException {
525            // create a Surfaces Array. Used to store the Surfaces the
526            // MultiSurface will consist of
527            Surface[] surfaces = new Surface[pgMultiPolygon.numPolygons()];
528            // for all Polygons the MultiPolygon consists of
529            for ( int i = 0; i < pgMultiPolygon.numPolygons(); i++ ) {
530                surfaces[i] = wrapSurface( pgMultiPolygon.getPolygon( i ), crs );
531            }
532    
533            return GeometryFactory.createMultiSurface( surfaces );
534        }
535    }