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