001 //$HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/base/branches/2.5_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 }