001 //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_testing/src/org/deegree/io/datastore/sql/postgis/PGgeometryAdapter.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
037 package org.deegree.io.datastore.sql.postgis;
038
039 import java.sql.SQLException;
040 import java.util.ArrayList;
041 import java.util.Iterator;
042 import java.util.List;
043
044 import org.deegree.model.crs.CoordinateSystem;
045 import org.deegree.model.spatialschema.Curve;
046 import org.deegree.model.spatialschema.Envelope;
047 import org.deegree.model.spatialschema.Geometry;
048 import org.deegree.model.spatialschema.GeometryException;
049 import org.deegree.model.spatialschema.GeometryFactory;
050 import org.deegree.model.spatialschema.MultiCurve;
051 import org.deegree.model.spatialschema.MultiGeometry;
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.GeometryCollection;
060 import org.postgis.LineString;
061 import org.postgis.MultiLineString;
062 import org.postgis.MultiPolygon;
063 import org.postgis.PGbox3d;
064 import org.postgis.PGboxbase;
065 import org.postgis.PGgeometry;
066 import org.postgis.Polygon;
067
068 /**
069 * Adapter between deegree <code>Geometry</code> objects and PostGIS <code>Geometry</code> 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: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $
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 {@link PGgeometry} object.
086 *
087 * @param geometry
088 * deegree <code>Geometry</code> to be converted
089 * @param srid
090 * PostGIS SRS id that is used to store the geometry
091 * @return corresponding PostGIS <code>Geometry</code>
092 * @throws GeometryException
093 */
094 public static PGgeometry export( Geometry geometry, int srid )
095 throws GeometryException {
096 PGgeometry pgGeometry = null;
097 if ( geometry instanceof Point ) {
098 pgGeometry = exportPoint( (Point) geometry, srid );
099 } else if ( geometry instanceof MultiPoint ) {
100 pgGeometry = exportMultiPoint( (MultiPoint) geometry, srid );
101 } else if ( geometry instanceof Curve ) {
102 pgGeometry = exportCurve( (Curve) geometry, srid );
103 } else if ( geometry instanceof MultiCurve ) {
104 pgGeometry = exportMultiCurve( (MultiCurve) geometry, srid );
105 } else if ( geometry instanceof Surface ) {
106 pgGeometry = exportSurface( (Surface) geometry, srid );
107 } else if ( geometry instanceof MultiSurface ) {
108 pgGeometry = exportMultiSurface( (MultiSurface) geometry, srid );
109 } else if ( geometry instanceof MultiGeometry ) {
110 pgGeometry = exportMultiGeometry( (MultiGeometry) geometry, srid );
111 } else {
112 throw new GeometryException( "Cannot export geometry of type '" + geometry.getClass()
113 + "' to PostGIS geometry: Unsupported type." );
114 }
115 return pgGeometry;
116 }
117
118 /**
119 * Converts a deegree <code>Envelope</code> instance to a corresponding PostGIS <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>PGGeometry</code> instance to a corresponding deegree <code>Geometry</code> object.
141 *
142 * @param pgGeometry
143 * PostGIS <code>PGgeometry</code> to be converted
144 * @param crs
145 * coordinate system of the created deegree <code>Geometry</code> object
146 * @return corresponding deegree <code>Geometry</code>
147 * @throws GeometryException
148 */
149 public static Geometry wrap( PGgeometry pgGeometry, CoordinateSystem crs )
150 throws GeometryException {
151 return wrap( pgGeometry.getGeometry(), crs );
152 }
153
154 /**
155 * Converts a PostGIS <code>Geometry</code> instance to a corresponding deegree <code>Geometry</code> object.
156 *
157 * @param geometry
158 * PostGIS <code>PGgeometry</code> to be converted
159 * @param crs
160 * coordinate system of the created deegree <code>Geometry</code> object
161 * @return corresponding deegree <code>Geometry</code>
162 * @throws GeometryException
163 */
164 public static Geometry wrap( org.postgis.Geometry geometry, CoordinateSystem crs )
165 throws GeometryException {
166 Geometry geo = null;
167
168 switch ( geometry.type ) {
169 case org.postgis.Geometry.POINT:
170 geo = wrapPoint( (org.postgis.Point) geometry, crs );
171 break;
172 case org.postgis.Geometry.LINESTRING:
173 geo = wrapCurve( (LineString) geometry, crs );
174 break;
175 case org.postgis.Geometry.POLYGON:
176 geo = wrapSurface( (Polygon) geometry, crs );
177 break;
178 case org.postgis.Geometry.MULTIPOINT:
179 geo = wrapMultiPoint( (org.postgis.MultiPoint) geometry, crs );
180 break;
181 case org.postgis.Geometry.MULTILINESTRING:
182 geo = wrapMultiCurve( (MultiLineString) geometry, crs );
183 break;
184 case org.postgis.Geometry.MULTIPOLYGON:
185 geo = wrapMultiSurface( (MultiPolygon) geometry, crs );
186 break;
187 case org.postgis.Geometry.GEOMETRYCOLLECTION:
188 geo = wrapMultiGeometry( (GeometryCollection) geometry, crs );
189 break;
190 default: {
191 throw new GeometryException( "Cannot export PostGIS geometry of type '" + geometry.getType()
192 + "' to deegree geometry: Unsupported type." );
193 }
194 }
195 return geo;
196 }
197
198 /**
199 * Creates a PostGIS <code>MultiPoint</code> from a deegree <code>Point</code>.
200 *
201 * @param point
202 * @param srid
203 * PostGIS SRS id that is used to store the geometry
204 * @throws GeometryException
205 */
206 private static PGgeometry exportPoint( Point point, int srid )
207 throws GeometryException {
208
209 StringBuffer sb = WKTAdapter.export( point );
210 org.postgis.Point pgPoint = null;
211
212 try {
213 pgPoint = new org.postgis.Point( sb.toString() );
214 } catch ( SQLException e ) {
215 throw new GeometryException( e.toString() );
216 }
217
218 pgPoint.setSrid( srid );
219 return new PGgeometry( pgPoint );
220 }
221
222 /**
223 * Creates a PostGIS <code>MultiPoint</code> from a deegree <code>MultiPoint</code>.
224 *
225 * @param multiPoint
226 * @param srid
227 * PostGIS SRS id that is used to store the geometry
228 * @throws GeometryException
229 */
230 private static PGgeometry exportMultiPoint( MultiPoint multiPoint, int srid )
231 throws GeometryException {
232
233 StringBuffer sb = WKTAdapter.export( multiPoint );
234 org.postgis.MultiPoint pgMPoint = null;
235
236 try {
237 pgMPoint = new org.postgis.MultiPoint( sb.toString() );
238 } catch ( Exception e ) {
239 throw new GeometryException( e.toString() );
240 }
241
242 pgMPoint.setSrid( srid );
243 return new PGgeometry( pgMPoint );
244 }
245
246 /**
247 * Creates a PostGIS <code>LineString</code> from a deegree <code>Curve</code>.
248 *
249 * @param curve
250 * @param srid
251 * PostGIS SRS id that is used to store the geometry
252 */
253 private static PGgeometry exportCurve( Curve curve, int srid )
254 throws GeometryException {
255 StringBuffer sb = WKTAdapter.export( curve );
256 org.postgis.LineString pgLineString = null;
257
258 try {
259 pgLineString = new org.postgis.LineString( sb.toString() );
260 } catch ( Exception e ) {
261 throw new GeometryException( e.toString() );
262 }
263
264 pgLineString.setSrid( srid );
265 return new PGgeometry( pgLineString );
266 }
267
268 /**
269 * Creates a PostGIS <code>org.postgis.MultiCurve</code> from a deegree <code>MultiCurve</code>.
270 *
271 * @param multiCurve
272 * @param srid
273 * PostGIS SRS id that is used to store the geometry
274 * @throws GeometryException
275 */
276 private static PGgeometry exportMultiCurve( MultiCurve multiCurve, int srid )
277 throws GeometryException {
278 StringBuffer sb = WKTAdapter.export( multiCurve );
279 org.postgis.MultiLineString pgMLineString = null;
280
281 try {
282 pgMLineString = new org.postgis.MultiLineString( sb.toString() );
283 } catch ( Exception e ) {
284 throw new GeometryException( e.toString() );
285 }
286
287 pgMLineString.setSrid( srid );
288 return new PGgeometry( pgMLineString );
289 }
290
291 /**
292 * Creates a PostGIS <code>Polygon</code> from a deegree <code>Surface</code>.
293 *
294 * @param surface
295 * @param srid
296 * PostGIS SRS id that is used to store the geometry
297 * @throws GeometryException
298 */
299 private static PGgeometry exportSurface( Surface surface, int srid )
300 throws GeometryException {
301 StringBuffer sb = WKTAdapter.export( surface );
302 org.postgis.Polygon pgPoly = null;
303
304 try {
305 pgPoly = new org.postgis.Polygon( sb.toString() );
306 } catch ( Exception e ) {
307 throw new GeometryException( e.toString() );
308 }
309
310 pgPoly.setSrid( srid );
311 return new PGgeometry( pgPoly );
312 }
313
314 /**
315 * Creates a PostGIS <code>MultiSurface</code> from a deegree <code>MultiSurface</code>.
316 *
317 * @param multiSurface
318 * @param srid
319 * PostGIS SRS id that is used to store the geometry
320 * @throws GeometryException
321 */
322 private static PGgeometry exportMultiSurface( MultiSurface multiSurface, int srid )
323 throws GeometryException {
324 StringBuffer sb = WKTAdapter.export( multiSurface );
325 org.postgis.MultiPolygon pgMPoly = null;
326
327 try {
328 pgMPoly = new org.postgis.MultiPolygon( sb.toString() );
329 } catch ( Exception e ) {
330 throw new GeometryException( e.toString() );
331 }
332
333 pgMPoly.setSrid( srid );
334 return new PGgeometry( pgMPoly );
335 }
336
337 /**
338 * Creates a PostGIS <code>GeometryCollection</code> from a deegree <code>MultiGeometry</code>.
339 *
340 * @param multiGeometry
341 * @param srid
342 * PostGIS SRS id that is used to store the geometry
343 * @throws GeometryException
344 */
345 private static PGgeometry exportMultiGeometry( MultiGeometry multiGeometry, int srid )
346 throws GeometryException {
347
348 StringBuffer sb = WKTAdapter.export( multiGeometry );
349 GeometryCollection pgGeometryCollection = null;
350
351 try {
352 pgGeometryCollection = new GeometryCollection( sb.toString() );
353 } catch ( Exception e ) {
354 throw new GeometryException( e.toString() );
355 }
356
357 pgGeometryCollection.setSrid( srid );
358 return new PGgeometry( pgGeometryCollection );
359 }
360
361 /**
362 * Creates a deegree <code>Point</code> from a PostGIS <code>Point</code>.
363 *
364 * @param pgPoint
365 * PostGIS <code>Point</code>
366 * @param crs
367 * coordinate system of the created deegree <code>Geometry</code> object
368 * @return deegree <code>Point</code>
369 */
370 private static Point wrapPoint( org.postgis.Point pgPoint, CoordinateSystem crs ) {
371 // if geometry is 2-dimensional
372 Position p = null;
373 if ( pgPoint.getDimension() == 2 ) {
374 // convert PostGIS Point to a Point using the GeometryFactory
375 p = GeometryFactory.createPosition( new double[] { pgPoint.getX(), pgPoint.getY() } );
376 // if geometry is 3-dimensional
377 } else if ( pgPoint.getDimension() == 3 ) {
378 // convert PostGIS Point to a Point using the GeometryFactory
379 p = GeometryFactory.createPosition( new double[] { pgPoint.getX(), pgPoint.getY(), pgPoint.getZ() } );
380 }
381 return GeometryFactory.createPoint( p, crs );
382 }
383
384 /**
385 * Creates a deegree <code>MultiPoint</code> from a PostGIS <code>MultiPoint</code>.
386 *
387 * @param pgMultiPoint
388 * PostGIS <code>MultiPoint</code>
389 * @param crs
390 * coordinate system of the created deegree <code>Geometry</code> object
391 * @return deegree <code>MultiPoint</code>
392 */
393 private static MultiPoint wrapMultiPoint( org.postgis.MultiPoint pgMultiPoint, CoordinateSystem crs ) {
394 // create a temporary Point Array to store the Points the
395 // MultiPoint will consist of
396 Point[] mpoints = new Point[pgMultiPoint.numPoints()];
397 // for all Points
398 for ( int i = 0; i < pgMultiPoint.numPoints(); i++ ) {
399 // convert PostGIS Point to a Point using the GeometryFactory
400 mpoints[i] = wrapPoint( pgMultiPoint.getPoint( i ), crs );
401 }
402 // create a Multipoint from the Array points
403 return GeometryFactory.createMultiPoint( mpoints );
404 }
405
406 /**
407 * Creates a deegree <code>Curve</code> from a PostGIS <code>LineString</code>.
408 *
409 * @param pgLineString
410 * PostGIS <code>LineString</code>
411 * @param crs
412 * coordinate system of the created deegree <code>Geometry</code> object
413 * @return deegree <code>Curve</code>
414 * @throws GeometryException
415 */
416 private static Curve wrapCurve( LineString pgLineString, CoordinateSystem crs )
417 throws GeometryException {
418 // create a Position Array. Used to store the Points the
419 // Curve will consist of
420 Position[] points = new Position[pgLineString.numPoints()];
421
422 // if geometry is 2-dimensional
423 if ( pgLineString.getDimension() == 2 ) {
424 // for all Points
425 for ( int i = 0; i < pgLineString.numPoints(); i++ ) {
426 // create a Position from the PostGIS Point using the
427 // GeometryFactory
428 double[] d = new double[] { pgLineString.getPoint( i ).getX(), pgLineString.getPoint( i ).getY() };
429 points[i] = GeometryFactory.createPosition( d );
430 }
431 // if geometry is 3-dimensional
432 } else if ( pgLineString.getDimension() == 3 ) {
433 // for all Points
434 for ( int i = 0; i < pgLineString.numPoints(); i++ ) {
435 // create a Position from the PostGIS Point using the
436 // GeometryFactory
437 double[] d = new double[] { pgLineString.getPoint( i ).getX(), pgLineString.getPoint( i ).getY(),
438 pgLineString.getPoint( i ).getZ() };
439 points[i] = GeometryFactory.createPosition( d );
440 }
441 }
442 return GeometryFactory.createCurve( points, crs );
443 }
444
445 /**
446 * Creates a deegree <code>MultiCurve</code> from a PostGIS <code>MultiLineString</code>.
447 *
448 * @param pgMultiLineString
449 * PostGIS <code>MultiLineString</code>
450 * @param crs
451 * coordinate system of the created deegree <code>Geometry</code> object
452 * @return deegree <code>MultiCurve</code>
453 * @throws GeometryException
454 */
455 private static MultiCurve wrapMultiCurve( MultiLineString pgMultiLineString, CoordinateSystem crs )
456 throws GeometryException {
457 // create a Curve Array. Used to store the CurveSegments the
458 // Curve will consist of
459 Curve[] curves = new Curve[pgMultiLineString.numLines()];
460 // for all Lines
461 for ( int i = 0; i < pgMultiLineString.numLines(); i++ ) {
462 // create a Curve form the positions Array using the
463 // GeometryFactory
464 curves[i] = wrapCurve( pgMultiLineString.getLine( i ), crs );
465 }
466 // create a Curve form all the CurveSegments stored in the
467 // csegments Array using the GeometryFactory
468 return GeometryFactory.createMultiCurve( curves );
469 }
470
471 /**
472 * Creates a deegree <code>Surface</code> from a PostGIS <code>Polygon</code>.
473 *
474 * @param pgPolygon
475 * PostGIS <code>Polygon</code>
476 * @param crs
477 * coordinate system of the created deegree <code>Geometry</code> object
478 * @return deegree <code>Surface</code>
479 * @throws GeometryException
480 */
481 private static Surface wrapSurface( Polygon pgPolygon, CoordinateSystem crs )
482 throws GeometryException {
483
484 // create a Position Array. Used to store the Positions the
485 // exterior Ring of the Surface will consist of
486 Position[] eRing = new Position[pgPolygon.getRing( 0 ).numPoints()];
487 // declares a Position[][] Array. Used to store the Positions
488 // of the interior Rings the Surface will consist of. The exterior
489 // Ring is stored seperately
490 Position[][] iRings = null;
491
492 // if geometry is 2-dimensional
493 if ( pgPolygon.getDimension() == 2 ) {
494 // for all the Points of the fist LinearRing (which is the exterior)
495 org.postgis.LinearRing ring = pgPolygon.getRing( 0 );
496 for ( int j = 0; j < eRing.length; j++ ) {
497 // store all the Points of the exterior Ring in the Array
498 // eRing. Convert them using GeometryFactory
499 double[] d = new double[] { ring.getPoint( j ).getX(), ring.getPoint( j ).getY() };
500 eRing[j] = GeometryFactory.createPosition( d );
501 }
502
503 if ( pgPolygon.numRings() > 1 ) {
504 iRings = new Position[pgPolygon.numRings() - 1][];
505 // for all LinearRings except the first one (which is the exterior one)
506 for ( int i = 1; i < pgPolygon.numRings(); i++ ) {
507 iRings[i - 1] = new Position[pgPolygon.getRing( i ).numPoints()];
508 // for all the Points in the ith LinearRing
509 ring = pgPolygon.getRing( i );
510 for ( int j = 0; j < ring.numPoints(); j++ ) {
511 // store all the Points of the ith interior Ring in
512 // the iRings Array
513 double[] d = new double[] { ring.getPoint( j ).getX(), ring.getPoint( j ).getY() };
514 iRings[i - 1][j] = GeometryFactory.createPosition( d );
515 }
516 }
517 }
518 // if geometry is 3-dimensional
519 } else if ( pgPolygon.getDimension() == 3 ) {
520 // for all the Points of the fist LinearRing (which is the exterior)
521 org.postgis.LinearRing ring = pgPolygon.getRing( 0 );
522 for ( int j = 0; j < ring.numPoints(); j++ ) {
523 // store all the Points of the exterior Ring in the Array
524 // eRing. Convert them using GeometryFactory
525 double[] d = new double[] { ring.getPoint( j ).getX(), ring.getPoint( j ).getY(),
526 ring.getPoint( j ).getZ() };
527 eRing[j] = GeometryFactory.createPosition( d );
528 }
529
530 if ( pgPolygon.numRings() > 1 ) {
531 iRings = new Position[pgPolygon.numRings() - 1][];
532 // for all LinearRings except the first one (which is the exterior one)
533 for ( int i = 1; i < pgPolygon.numRings(); i++ ) {
534 iRings[i - 1] = new Position[pgPolygon.getRing( i ).numPoints()];
535 // for all the Points in the ith LinearRing
536 ring = pgPolygon.getRing( i );
537 for ( int j = 0; j < ring.numPoints(); j++ ) {
538 // store all the Points of the ith interior Ring in the iRings Array
539 double[] d = new double[] { ring.getPoint( j ).getX(), ring.getPoint( j ).getY(),
540 ring.getPoint( j ).getZ() };
541 iRings[i - 1][j] = GeometryFactory.createPosition( d );
542 }
543 }
544 }
545 }
546
547 return GeometryFactory.createSurface( eRing, iRings, new SurfaceInterpolationImpl(), crs );
548 }
549
550 /**
551 * Creates a deegree <code>MultiSurface</code> from a PostGIS <code>MultiPolygon</code>.
552 *
553 * @param pgMultiPolygon
554 * PostGIS <code>MultiPolygon</code>
555 * @param crs
556 * coordinate system of the created deegree <code>Geometry</code> object
557 * @return deegree <code>MultiSurface</code>
558 * @throws GeometryException
559 */
560 private static MultiSurface wrapMultiSurface( MultiPolygon pgMultiPolygon, CoordinateSystem crs )
561 throws GeometryException {
562 // create a Surfaces Array. Used to store the Surfaces the
563 // MultiSurface will consist of
564 Surface[] surfaces = new Surface[pgMultiPolygon.numPolygons()];
565 // for all Polygons the MultiPolygon consists of
566 for ( int i = 0; i < pgMultiPolygon.numPolygons(); i++ ) {
567 surfaces[i] = wrapSurface( pgMultiPolygon.getPolygon( i ), crs );
568 }
569
570 return GeometryFactory.createMultiSurface( surfaces );
571 }
572
573 /**
574 * Creates a deegree <code>MultiGeometry</code> from a PostGIS <code>GeometryCollection</code>.
575 *
576 * @param pgGeometryCollection
577 * PostGIS <code>GeometryCollection</code>
578 * @param crs
579 * coordinate system of the created deegree <code>Geometry</code> object
580 * @return deegree <code>MultiGeometry</code>
581 * @throws GeometryException
582 */
583 private static MultiGeometry wrapMultiGeometry( GeometryCollection pgGeometryCollection, CoordinateSystem crs )
584 throws GeometryException {
585
586 List<Geometry> members = new ArrayList<Geometry>();
587 Iterator<?> memberIter = pgGeometryCollection.iterator();
588 while ( memberIter.hasNext() ) {
589 org.postgis.Geometry memberGeometry = (org.postgis.Geometry) memberIter.next();
590 members.add( wrap( memberGeometry, crs ) );
591 }
592 return GeometryFactory.createMultiGeometry( members.toArray( new Geometry[members.size()] ), crs );
593 }
594 }