Rev 229 | Blame | Compare with Previous | Last modification | View Log | RSS feed
/*** $Id: PGGeometryUserType.java 243 2010-09-22 20:41:23Z maesenka $** This file is part of Hibernate Spatial, an extension to the* hibernate ORM solution for geographic data.** Copyright © 2007 Geovise BVBA* Copyright © 2007 K.U. Leuven LRD, Spatial Applications Division, Belgium** This work was partially supported by the European Commission,* under the 6th Framework Programme, contract IST-2-004688-STP.** This library is free software; you can redistribute it and/or* modify it under the terms of the GNU Lesser General Public* License as published by the Free Software Foundation; either* version 2.1 of the License, or (at your option) any later version.** This library is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU* Lesser General Public License for more details.** You should have received a copy of the GNU Lesser General Public* License along with this library; if not, write to the Free Software* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA** For more information, visit: http://www.hibernatespatial.org/*/package org.hibernatespatial.postgis;import com.vividsolutions.jts.geom.Coordinate;import com.vividsolutions.jts.geom.Geometry;import com.vividsolutions.jts.geom.GeometryFactory;import org.hibernatespatial.AbstractDBGeometryType;import org.hibernatespatial.HBSpatialExtension;import org.hibernatespatial.mgeom.MCoordinate;import org.hibernatespatial.mgeom.MGeometry;import org.hibernatespatial.mgeom.MLineString;import org.postgis.*;import java.sql.Connection;import java.sql.Types;/*** Specific <code>GeometryType</code> for Postgis geometry type** @author Karel Maesen*/public class PGGeometryUserType extends AbstractDBGeometryType {private static final int[] geometryTypes = new int[]{Types.STRUCT};public int[] sqlTypes() {return geometryTypes;}/*** Converts the native geometry object to a JTS <code>Geometry</code>.** @param object native database geometry object (depends on the JDBC spatial* extension of the database)* @return JTS geometry corresponding to geomObj.*/public Geometry convert2JTS(Object object) {if (object == null)return null;// in some cases, Postgis returns not PGgeometry objects// but org.postgis.Geometry instances.// This has been observed when retrieving GeometryCollections// as the result of an SQL-operation such as Union.if (object instanceof org.postgis.Geometry) {object = new PGgeometry((org.postgis.Geometry) object);}if (object instanceof PGgeometry) {PGgeometry geom = (PGgeometry) object;com.vividsolutions.jts.geom.Geometry out = null;switch (geom.getGeoType()) {case org.postgis.Geometry.POINT:out = convertPoint((org.postgis.Point) geom.getGeometry());break;case org.postgis.Geometry.LINESTRING:out = convertLineString((org.postgis.LineString) geom.getGeometry());break;case org.postgis.Geometry.POLYGON:out = convertPolygon((org.postgis.Polygon) geom.getGeometry());break;case org.postgis.Geometry.MULTILINESTRING:out = convertMultiLineString((org.postgis.MultiLineString) geom.getGeometry());break;case org.postgis.Geometry.MULTIPOINT:out = convertMultiPoint((org.postgis.MultiPoint) geom.getGeometry());break;case org.postgis.Geometry.MULTIPOLYGON:out = convertMultiPolygon((org.postgis.MultiPolygon) geom.getGeometry());break;case org.postgis.Geometry.GEOMETRYCOLLECTION:out = convertGeometryCollection((org.postgis.GeometryCollection) geom.getGeometry());break;default:throw new RuntimeException("Unknown type of PGgeometry");}out.setSRID(geom.getGeometry().srid);return out;} else if (object instanceof org.postgis.PGboxbase) {return convertBox((org.postgis.PGboxbase) object);} else {throw new IllegalArgumentException("Can't convert object of type "+ object.getClass().getCanonicalName());}}private Geometry convertBox(PGboxbase box) {Point ll = box.getLLB();Point ur = box.getURT();Coordinate[] ringCoords = new Coordinate[5];if (box instanceof org.postgis.PGbox2d) {ringCoords[0] = new Coordinate(ll.x, ll.y);ringCoords[1] = new Coordinate(ur.x, ll.y);ringCoords[2] = new Coordinate(ur.x, ur.y);ringCoords[3] = new Coordinate(ll.x, ur.y);ringCoords[4] = new Coordinate(ll.x, ll.y);} else {ringCoords[0] = new Coordinate(ll.x, ll.y, ll.z);ringCoords[1] = new Coordinate(ur.x, ll.y, ll.z);ringCoords[2] = new Coordinate(ur.x, ur.y, ur.z);ringCoords[3] = new Coordinate(ll.x, ur.y, ur.z);ringCoords[4] = new Coordinate(ll.x, ll.y, ll.z);}com.vividsolutions.jts.geom.LinearRing shell = getGeometryFactory().createLinearRing(ringCoords);return getGeometryFactory().createPolygon(shell, null);}private Geometry convertGeometryCollection(GeometryCollection collection) {org.postgis.Geometry[] geometries = collection.getGeometries();com.vividsolutions.jts.geom.Geometry[] jtsGeometries = new com.vividsolutions.jts.geom.Geometry[geometries.length];for (int i = 0; i < geometries.length; i++) {jtsGeometries[i] = convert2JTS(geometries[i]);//TODO - refactor this so the following line is not necessaryjtsGeometries[i].setSRID(0); // convert2JTS sets SRIDs, but constituent geometries in a collection must have srid == 0}com.vividsolutions.jts.geom.GeometryCollection jtsGCollection = getGeometryFactory().createGeometryCollection(jtsGeometries);return jtsGCollection;}private Geometry convertMultiPolygon(MultiPolygon pgMultiPolygon) {com.vividsolutions.jts.geom.Polygon[] polygons = new com.vividsolutions.jts.geom.Polygon[pgMultiPolygon.numPolygons()];for (int i = 0; i < polygons.length; i++) {Polygon pgPolygon = pgMultiPolygon.getPolygon(i);polygons[i] = (com.vividsolutions.jts.geom.Polygon) convertPolygon(pgPolygon);}com.vividsolutions.jts.geom.MultiPolygon out = getGeometryFactory().createMultiPolygon(polygons);return out;}private Geometry convertMultiPoint(MultiPoint pgMultiPoint) {com.vividsolutions.jts.geom.Point[] points = new com.vividsolutions.jts.geom.Point[pgMultiPoint.numPoints()];for (int i = 0; i < points.length; i++) {points[i] = convertPoint(pgMultiPoint.getPoint(i));}com.vividsolutions.jts.geom.MultiPoint out = getGeometryFactory().createMultiPoint(points);out.setSRID(pgMultiPoint.srid);return out;}private com.vividsolutions.jts.geom.Geometry convertMultiLineString(MultiLineString mlstr) {com.vividsolutions.jts.geom.MultiLineString out;if (mlstr.haveMeasure) {MLineString[] lstrs = new MLineString[mlstr.numLines()];for (int i = 0; i < mlstr.numLines(); i++) {MCoordinate[] coordinates = toJTSCoordinates(mlstr.getLine(i).getPoints());lstrs[i] = getGeometryFactory().createMLineString(coordinates);}out = getGeometryFactory().createMultiMLineString(lstrs);} else {com.vividsolutions.jts.geom.LineString[] lstrs = new com.vividsolutions.jts.geom.LineString[mlstr.numLines()];for (int i = 0; i < mlstr.numLines(); i++) {lstrs[i] = getGeometryFactory().createLineString(toJTSCoordinates(mlstr.getLine(i).getPoints()));}out = getGeometryFactory().createMultiLineString(lstrs);}return out;}protected com.vividsolutions.jts.geom.Geometry convertPolygon(Polygon polygon) {com.vividsolutions.jts.geom.LinearRing shell = getGeometryFactory().createLinearRing(toJTSCoordinates(polygon.getRing(0).getPoints()));com.vividsolutions.jts.geom.Polygon out = null;if (polygon.numRings() > 1) {com.vividsolutions.jts.geom.LinearRing[] rings = new com.vividsolutions.jts.geom.LinearRing[polygon.numRings() - 1];for (int r = 1; r < polygon.numRings(); r++) {rings[r - 1] = getGeometryFactory().createLinearRing(toJTSCoordinates(polygon.getRing(r).getPoints()));}out = getGeometryFactory().createPolygon(shell, rings);} else {out = getGeometryFactory().createPolygon(shell, null);}return out;}protected com.vividsolutions.jts.geom.Point convertPoint(Point pnt) {com.vividsolutions.jts.geom.Point g = getGeometryFactory().createPoint(this.toJTSCoordinate(pnt));return g;}protected com.vividsolutions.jts.geom.LineString convertLineString(org.postgis.LineString lstr) {com.vividsolutions.jts.geom.LineString out = lstr.haveMeasure ? getGeometryFactory().createMLineString(toJTSCoordinates(lstr.getPoints())): getGeometryFactory().createLineString(toJTSCoordinates(lstr.getPoints()));return out;}private MCoordinate[] toJTSCoordinates(Point[] points) {MCoordinate[] coordinates = new MCoordinate[points.length];for (int i = 0; i < points.length; i++) {coordinates[i] = this.toJTSCoordinate(points[i]);}return coordinates;}private MCoordinate toJTSCoordinate(Point pt) {MCoordinate mc;if (pt.dimension == 2) {mc = pt.haveMeasure ? MCoordinate.create2dWithMeasure(pt.getX(), pt.getY(), pt.getM()) : MCoordinate.create2d(pt.getX(), pt.getY());} else {mc = pt.haveMeasure ? MCoordinate.create3dWithMeasure(pt.getX(), pt.getY(), pt.getZ(), pt.getM()) : MCoordinate.create3d(pt.getX(), pt.getY(), pt.getZ());}return mc;}private Point[] toPoints(Coordinate[] coordinates) {Point[] points = new Point[coordinates.length];for (int i = 0; i < coordinates.length; i++) {Coordinate c = coordinates[i];Point pt;if (Double.isNaN(c.z)) {pt = new Point(c.x, c.y);} else {pt = new Point(c.x, c.y, c.z);}if (c instanceof MCoordinate) {MCoordinate mc = (MCoordinate) c;if (!Double.isNaN(mc.m)) {pt.setM(mc.m);}}points[i] = pt;}return points;}/*** Converts a JTS <code>Geometry</code> to a native geometry object.** @param jtsGeom JTS Geometry to convert* @param connection the current database connection* @return native database geometry object corresponding to jtsGeom.*/public Object conv2DBGeometry(Geometry jtsGeom, Connection connection) {org.postgis.Geometry geom = null;jtsGeom = forceEmptyToGeometryCollection(jtsGeom);if (jtsGeom instanceof com.vividsolutions.jts.geom.Point) {geom = convertJTSPoint((com.vividsolutions.jts.geom.Point) jtsGeom);} else if (jtsGeom instanceof com.vividsolutions.jts.geom.LineString) {geom = convertJTSLineString((com.vividsolutions.jts.geom.LineString) jtsGeom);} else if (jtsGeom instanceof com.vividsolutions.jts.geom.MultiLineString) {geom = convertJTSMultiLineString((com.vividsolutions.jts.geom.MultiLineString) jtsGeom);} else if (jtsGeom instanceof com.vividsolutions.jts.geom.Polygon) {geom = convertJTSPolygon((com.vividsolutions.jts.geom.Polygon) jtsGeom);} else if (jtsGeom instanceof com.vividsolutions.jts.geom.MultiPoint) {geom = convertJTSMultiPoint((com.vividsolutions.jts.geom.MultiPoint) jtsGeom);} else if (jtsGeom instanceof com.vividsolutions.jts.geom.MultiPolygon) {geom = convertJTSMultiPolygon((com.vividsolutions.jts.geom.MultiPolygon) jtsGeom);} else if (jtsGeom instanceof com.vividsolutions.jts.geom.GeometryCollection) {geom = convertJTSGeometryCollection((com.vividsolutions.jts.geom.GeometryCollection) jtsGeom);}if (geom != null)return new PGgeometry(geom);elsethrow new UnsupportedOperationException("Conversion of "+ jtsGeom.getClass().getSimpleName()+ " to PGgeometry not supported");}//Postgis treats every empty geometry as an empty geometrycollectionprivate Geometry forceEmptyToGeometryCollection(Geometry jtsGeom) {Geometry forced = jtsGeom;if (forced.isEmpty()) {GeometryFactory factory = jtsGeom.getFactory();if (factory == null) {factory = HBSpatialExtension.getDefaultGeomFactory();}forced = factory.createGeometryCollection(null);forced.setSRID(jtsGeom.getSRID());}return forced;}private MultiPolygon convertJTSMultiPolygon(com.vividsolutions.jts.geom.MultiPolygon multiPolygon) {Polygon[] pgPolygons = new Polygon[multiPolygon.getNumGeometries()];for (int i = 0; i < pgPolygons.length; i++) {pgPolygons[i] = convertJTSPolygon((com.vividsolutions.jts.geom.Polygon) multiPolygon.getGeometryN(i));}MultiPolygon mpg = new MultiPolygon(pgPolygons);mpg.setSrid(multiPolygon.getSRID());return mpg;}private MultiPoint convertJTSMultiPoint(com.vividsolutions.jts.geom.MultiPoint multiPoint) {Point[] pgPoints = new Point[multiPoint.getNumGeometries()];for (int i = 0; i < pgPoints.length; i++) {pgPoints[i] = convertJTSPoint((com.vividsolutions.jts.geom.Point) multiPoint.getGeometryN(i));}MultiPoint mp = new MultiPoint(pgPoints);mp.setSrid(multiPoint.getSRID());return mp;}private Polygon convertJTSPolygon(com.vividsolutions.jts.geom.Polygon jtsPolygon) {int numRings = jtsPolygon.getNumInteriorRing();org.postgis.LinearRing[] rings = new org.postgis.LinearRing[numRings + 1];rings[0] = convertJTSLineStringToLinearRing(jtsPolygon.getExteriorRing());for (int i = 0; i < numRings; i++) {rings[i + 1] = convertJTSLineStringToLinearRing(jtsPolygon.getInteriorRingN(i));}Polygon polygon = new org.postgis.Polygon(rings);polygon.setSrid(jtsPolygon.getSRID());return polygon;}private LinearRing convertJTSLineStringToLinearRing(com.vividsolutions.jts.geom.LineString lineString) {LinearRing lr = new org.postgis.LinearRing(toPoints(lineString.getCoordinates()));lr.setSrid(lineString.getSRID());return lr;}private LineString convertJTSLineString(com.vividsolutions.jts.geom.LineString string) {LineString ls = new org.postgis.LineString(toPoints(string.getCoordinates()));if (string instanceof MGeometry) {ls.haveMeasure = true;}ls.setSrid(string.getSRID());return ls;}private MultiLineString convertJTSMultiLineString(com.vividsolutions.jts.geom.MultiLineString string) {org.postgis.LineString[] lines = new org.postgis.LineString[string.getNumGeometries()];for (int i = 0; i < string.getNumGeometries(); i++) {lines[i] = new org.postgis.LineString(toPoints(string.getGeometryN(i).getCoordinates()));}MultiLineString mls = new MultiLineString(lines);if (string instanceof MGeometry) {mls.haveMeasure = true;}mls.setSrid(string.getSRID());return mls;}private Point convertJTSPoint(com.vividsolutions.jts.geom.Point point) {org.postgis.Point pgPoint = new org.postgis.Point();pgPoint.srid = point.getSRID();pgPoint.x = point.getX();pgPoint.y = point.getY();Coordinate coordinate = point.getCoordinate();if (Double.isNaN(coordinate.z)) {pgPoint.dimension = 2;} else {pgPoint.z = coordinate.z;pgPoint.dimension = 3;}pgPoint.haveMeasure = false;if (coordinate instanceof MCoordinate && !Double.isNaN(((MCoordinate) coordinate).m)) {pgPoint.m = ((MCoordinate) coordinate).m;pgPoint.haveMeasure = true;}return pgPoint;}private GeometryCollection convertJTSGeometryCollection(com.vividsolutions.jts.geom.GeometryCollection collection) {com.vividsolutions.jts.geom.Geometry currentGeom;org.postgis.Geometry[] pgCollections = new org.postgis.Geometry[collection.getNumGeometries()];for (int i = 0; i < pgCollections.length; i++) {currentGeom = collection.getGeometryN(i);currentGeom = forceEmptyToGeometryCollection(currentGeom);if (currentGeom.getClass() == com.vividsolutions.jts.geom.LineString.class) {pgCollections[i] = convertJTSLineString((com.vividsolutions.jts.geom.LineString) currentGeom);} else if (currentGeom.getClass() == com.vividsolutions.jts.geom.LinearRing.class) {pgCollections[i] = convertJTSLineStringToLinearRing((com.vividsolutions.jts.geom.LinearRing) currentGeom);} else if (currentGeom.getClass() == com.vividsolutions.jts.geom.MultiLineString.class) {pgCollections[i] = convertJTSMultiLineString((com.vividsolutions.jts.geom.MultiLineString) currentGeom);} else if (currentGeom.getClass() == com.vividsolutions.jts.geom.MultiPoint.class) {pgCollections[i] = convertJTSMultiPoint((com.vividsolutions.jts.geom.MultiPoint) currentGeom);} else if (currentGeom.getClass() == com.vividsolutions.jts.geom.MultiPolygon.class) {pgCollections[i] = convertJTSMultiPolygon((com.vividsolutions.jts.geom.MultiPolygon) currentGeom);} else if (currentGeom.getClass() == com.vividsolutions.jts.geom.Point.class) {pgCollections[i] = convertJTSPoint((com.vividsolutions.jts.geom.Point) currentGeom);} else if (currentGeom.getClass() == com.vividsolutions.jts.geom.Polygon.class) {pgCollections[i] = convertJTSPolygon((com.vividsolutions.jts.geom.Polygon) currentGeom);} else if (currentGeom.getClass() == com.vividsolutions.jts.geom.GeometryCollection.class) {pgCollections[i] = convertJTSGeometryCollection((com.vividsolutions.jts.geom.GeometryCollection) currentGeom);}}GeometryCollection gc = new GeometryCollection(pgCollections);gc.setSrid(collection.getSRID());return gc;}}