/*
* JBoss, Home of Professional Open Source.
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership. Some portions may be licensed
* to Red Hat, Inc. under one or more contributor license agreements.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA.
*/
package org.teiid.query.function;
import org.osgeo.proj4j.CRSFactory;
import org.osgeo.proj4j.CoordinateReferenceSystem;
import org.osgeo.proj4j.CoordinateTransform;
import org.osgeo.proj4j.CoordinateTransformFactory;
import org.osgeo.proj4j.ProjCoordinate;
import org.teiid.CommandContext;
import org.teiid.core.types.GeometryType;
import org.teiid.runtime.client.Messages;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryCollection;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.LinearRing;
import com.vividsolutions.jts.geom.MultiLineString;
import com.vividsolutions.jts.geom.MultiPoint;
import com.vividsolutions.jts.geom.MultiPolygon;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.Polygon;
/**
* Wrapper around proj4j library to transform geometries to different coordinate
* systems (ST_Transform).
*/
public class GeometryTransformUtils {
/**
* Convert geometry to a different coordinate system. Geometry must have valid
* SRID.
*
* @param ctx Command context used to lookup proj4 parameters from table.
* @param geom Geometry to transform.
* @param srid Target SRID; must exist in SPATIAL_REF_SYS table.
* @return Reprojected geometry.
* @throws Exception
*/
public static GeometryType transform(CommandContext ctx, GeometryType geom, int srid) throws Exception {
Geometry jtsGeomSrc = GeometryUtils.getGeometry(geom);
Geometry jtsGeomTgt = transform(ctx, jtsGeomSrc, srid);
return GeometryUtils.getGeometryType(jtsGeomTgt, srid);
}
/**
* Convert the raw geometry to the target srid coordinate system.
* @param ctx Command context used to lookup proj4 parameters from table.
* @param jtsGeomSrc Geometry to transform.
* @param srid Target SRID; must exist in SPATIAL_REF_SYS table.
* @return
* @throws Exception
*/
static Geometry transform(CommandContext ctx, Geometry jtsGeomSrc, int srid) throws Exception {
String srcParam = lookupProj4Text(ctx, jtsGeomSrc.getSRID());
String tgtParam = lookupProj4Text(ctx, srid);
Geometry jtsGeomTgt = transform(jtsGeomSrc, srcParam, tgtParam);
return jtsGeomTgt;
}
/**
* Lookup proj4 parameters in SPATIAL_REF_SYS using SRID as key.
*
* @param ctx
* @param srid
* @return
* @throws Exception
*/
public static String lookupProj4Text(CommandContext ctx, int srid) throws Exception {
/*
* TODO
* Designer will need to handle this in a different way since we do not want to
* query the teiid server just to retrieve the String value for the given srid. We
* should be able to interrogate the spatial_ref_sys csv file for example.
*/
throw new UnsupportedOperationException("Geometry lookup facilities disabled at this time"); //$NON-NLS-1$
// String projText;
// PreparedStatement pstmt = null;
// ResultSet rs = null;
//
// try {
// TeiidConnection conn = ctx.getConnection();
// pstmt = conn.prepareStatement("select proj4text from spatial_ref_sys where srid = ?"); //$NON-NLS-1$
// pstmt.setInt(1, srid);
// rs = pstmt.executeQuery();
// if (!rs.next()) {
// throw new TeiidClientException(Messages.gs(Messages.TEIID.TEIID31162, srid));
// }
// projText = rs.getString(1);
// } catch (SQLException e) {
// throw new TeiidClientException(e, Messages.gs(Messages.TEIID.TEIID31163));
// } finally {
// try {
// if (rs != null) {
// rs.close();
// }
// } catch (Exception e) {
// // ignore
// }
// try {
// if (pstmt != null) {
// pstmt.close();
// }
// } catch (Exception e) {
// // ignore
// }
// }
//
// return projText;
}
/**
* Convert geometry to different coordinate system given the source/target
* proj4 parameters. Presumably these were pulled from SPATIAL_REF_SYS.
*
* @param geom
* @param srcParams
* @param tgtParams
* @return
* @throws Exception
*/
public static Geometry transform(Geometry geom, String srcParams, String tgtParams) throws Exception {
CoordinateTransformFactory ctFactory = new CoordinateTransformFactory();
CRSFactory crsFactory = new CRSFactory();
CoordinateReferenceSystem srcCrs = crsFactory.createFromParameters(null, srcParams);
CoordinateReferenceSystem tgtCrs = crsFactory.createFromParameters(null, tgtParams);
CoordinateTransform coordTransform = ctFactory.createTransform(srcCrs, tgtCrs);
return transformGeometry(coordTransform, geom);
}
protected static Geometry transformGeometry(CoordinateTransform ct, Geometry geom) throws Exception {
if (geom instanceof Polygon) {
return transformPolygon(ct, (Polygon)geom);
} else if (geom instanceof Point) {
return transformPoint(ct, (Point)geom);
} else if (geom instanceof LinearRing) {
return transformLinearRing(ct, (LinearRing)geom);
} else if (geom instanceof LineString) {
return transformLineString(ct, (LineString)geom);
} else if (geom instanceof MultiPolygon) {
return transformMultiPolygon(ct, (MultiPolygon)geom);
} else if (geom instanceof MultiPoint) {
return transformMultiPoint(ct, (MultiPoint)geom);
} else if (geom instanceof MultiLineString) {
return transformMultiLineString(ct, (MultiLineString)geom);
} else if (geom instanceof GeometryCollection) {
return transformGeometryCollection(ct, (GeometryCollection)geom);
} else {
throw new Exception(Messages.gs(Messages.TEIID.TEIID31164, geom.getGeometryType()));
}
}
/**
* Convert proj4 coordinates to JTS coordinates.
*
* @param projCoords
* @return
*/
protected static Coordinate[] convert(ProjCoordinate[] projCoords) {
Coordinate[] jtsCoords = new Coordinate[projCoords.length];
for (int i = 0; i < projCoords.length; ++i) {
jtsCoords[i] = new Coordinate(projCoords[i].x, projCoords[i].y);
}
return jtsCoords;
}
/**
* Convert JTS coordinates to proj4j coordinates.
*
* @param jtsCoords
* @return
*/
protected static ProjCoordinate[] convert(Coordinate[] jtsCoords) {
ProjCoordinate[] projCoords = new ProjCoordinate[jtsCoords.length];
for (int i = 0; i < jtsCoords.length; ++i) {
projCoords[i] = new ProjCoordinate(jtsCoords[i].x, jtsCoords[i].y);
}
return projCoords;
}
protected static Coordinate[] transformCoordinates(CoordinateTransform ct, Coordinate[] in) {
return convert(transformCoordinates(ct, convert(in)));
}
protected static ProjCoordinate[] transformCoordinates(CoordinateTransform ct, ProjCoordinate[] in) {
ProjCoordinate[] out = new ProjCoordinate[in.length];
for (int i = 0; i < in.length; ++i) {
out[i] = ct.transform(in[i], new ProjCoordinate());
}
return out;
}
protected static Polygon transformPolygon(CoordinateTransform ct, Polygon polygon) {
return polygon.getFactory().createPolygon(transformCoordinates(ct, polygon.getCoordinates()));
}
protected static Geometry transformPoint(CoordinateTransform ct, Point point) {
return point.getFactory().createPoint(transformCoordinates(ct, point.getCoordinates())[0]);
}
protected static Geometry transformLinearRing(CoordinateTransform ct, LinearRing linearRing) {
return linearRing.getFactory().createLinearRing(transformCoordinates(ct, linearRing.getCoordinates()));
}
protected static Geometry transformLineString(CoordinateTransform ct, LineString lineString) {
return lineString.getFactory().createLineString(transformCoordinates(ct, lineString.getCoordinates()));
}
protected static Geometry transformMultiPolygon(CoordinateTransform ct, MultiPolygon multiPolygon) {
Polygon[] polygon = new Polygon[multiPolygon.getNumGeometries()];
for (int i = 0; i < polygon.length; ++i) {
polygon[i] = multiPolygon.getFactory().createPolygon(transformCoordinates(ct,
multiPolygon.getGeometryN(i).getCoordinates()));
}
return multiPolygon.getFactory().createMultiPolygon(polygon);
}
protected static Geometry transformMultiPoint(CoordinateTransform ct, MultiPoint multiPoint) {
return multiPoint.getFactory().createMultiPoint(transformCoordinates(ct, multiPoint.getCoordinates()));
}
protected static Geometry transformMultiLineString(CoordinateTransform ct, MultiLineString multiLineString) {
LineString[] lineString = new LineString[multiLineString.getNumGeometries()];
for (int i = 0; i < lineString.length; ++i) {
lineString[i] = multiLineString.getFactory().createLineString(transformCoordinates(ct,
multiLineString.getGeometryN(i).getCoordinates()));
}
return multiLineString.getFactory().createMultiLineString(lineString);
}
protected static Geometry transformGeometryCollection(CoordinateTransform ct, GeometryCollection geometryCollection)
throws Exception {
Geometry[] geometry = new Geometry[geometryCollection.getNumGeometries()];
for (int i = 0; i < geometry.length; ++i) {
geometry[i] = transformGeometry(ct, geometryCollection.getGeometryN(i));
}
return geometryCollection.getFactory().createGeometryCollection(geometry);
}
}