/***************************************************
*
* cismet GmbH, Saarbruecken, Germany
*
* ... and it just works.
*
****************************************************/
package de.cismet.cismap.commons;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.PrecisionModel;
import edu.umd.cs.piccolo.PNode;
import org.apache.log4j.Logger;
import org.deegree.crs.components.Unit;
import org.deegree.model.crs.CRSFactory;
import org.deegree.model.crs.CRSTransformationException;
import org.deegree.model.crs.CoordinateSystem;
import org.deegree.model.crs.GeoTransformer;
import org.deegree.model.crs.UnknownCRSException;
import org.deegree.model.spatialschema.Geometry;
import org.deegree.model.spatialschema.GeometryException;
import org.deegree.model.spatialschema.GeometryFactory;
import org.deegree.model.spatialschema.JTSAdapter;
import org.deegree.model.spatialschema.Point;
import org.deegree.ogcwebservices.wcts.data.GeometryData;
import java.security.InvalidParameterException;
import java.util.List;
import de.cismet.cismap.commons.interaction.CismapBroker;
/**
* DOCUMENT ME!
*
* @author therter
* @version $Revision$, $Date$
*/
public class CrsTransformer {
//~ Static fields/initializers ---------------------------------------------
private static final transient Logger LOG = Logger.getLogger(CrsTransformer.class);
//~ Instance fields --------------------------------------------------------
private GeoTransformer transformer;
private CoordinateSystem crs;
private String destCrsAsString;
//~ Constructors -----------------------------------------------------------
/**
* Creates a new CrsTransformer object.
*
* @param destCrs the destination crs in the form "EPSG:XXXX"
*
* @throws UnknownCRSException DOCUMENT ME!
* @throws InvalidParameterException DOCUMENT ME!
*/
public CrsTransformer(final String destCrs) throws UnknownCRSException, InvalidParameterException {
this.destCrsAsString = destCrs;
transformer = new GeoTransformer(destCrs);
crs = CRSFactory.create(destCrs);
}
//~ Methods ----------------------------------------------------------------
/**
* DOCUMENT ME!
*
* @return the destination crs in the form "EPSG:XXXX"
*/
/**
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public String getDestinationCrs() {
return destCrsAsString;
}
/**
* DOCUMENT ME!
*
* @param bbox DOCUMENT ME!
* @param sourceCrs DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @throws UnknownCRSException DOCUMENT ME!
* @throws CRSTransformationException DOCUMENT ME!
* @throws IllegalArgumentException DOCUMENT ME!
*/
public BoundingBox transformBoundingBox(final BoundingBox bbox, String sourceCrs) throws UnknownCRSException,
CRSTransformationException,
IllegalArgumentException {
if (isDefaultCrs(sourceCrs)) {
sourceCrs = CismapBroker.getInstance().getDefaultCrs();
}
final CoordinateSystem coordSystem = CRSFactory.create(sourceCrs);
Point minPoint = GeometryFactory.createPoint(bbox.getX1(), bbox.getY1(), coordSystem);
Point maxPoint = GeometryFactory.createPoint(bbox.getX2(), bbox.getY2(), coordSystem);
if ((extractSridFromCrs(sourceCrs) == 3857)
&& ((extractSridFromCrs(destCrsAsString) == 31466)
|| (extractSridFromCrs(destCrsAsString) == 31467))) {
// To transform a geometry from 3857 to 31466/31467, the geometry should be first transformed to an other
// crs and then to 31466/31467. Otherwise, the transformation is not correct
final GeoTransformer transformer4326 = new GeoTransformer("EPSG:4326");
minPoint = (org.deegree.model.spatialschema.Point)transformer4326.transform(minPoint);
maxPoint = (org.deegree.model.spatialschema.Point)transformer4326.transform(maxPoint);
minPoint = (org.deegree.model.spatialschema.Point)transformer.transform(minPoint);
maxPoint = (org.deegree.model.spatialschema.Point)transformer.transform(maxPoint);
} else {
minPoint = (org.deegree.model.spatialschema.Point)transformer.transform(minPoint);
maxPoint = (org.deegree.model.spatialschema.Point)transformer.transform(maxPoint);
}
BoundingBox newBbox;
if (bbox instanceof XBoundingBox) {
newBbox = new XBoundingBox(minPoint.getX(),
minPoint.getY(),
maxPoint.getX(),
maxPoint.getY(),
crs.getIdentifier(),
crs.getAxisUnits()[0].equals(Unit.METRE));
} else {
newBbox = new BoundingBox(minPoint.getX(), minPoint.getY(), maxPoint.getX(), maxPoint.getY());
}
return newBbox;
}
/**
* DOCUMENT ME!
*
* @param bbox DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @throws UnknownCRSException DOCUMENT ME!
* @throws CRSTransformationException DOCUMENT ME!
* @throws IllegalArgumentException DOCUMENT ME!
*/
public XBoundingBox transformBoundingBox(final XBoundingBox bbox) throws UnknownCRSException,
CRSTransformationException,
IllegalArgumentException {
return (XBoundingBox)transformBoundingBox(bbox, bbox.getSrs());
}
/**
* DOCUMENT ME!
*
* @param sourceCrs DOCUMENT ME!
* @param coords coords <T> DOCUMENT ME!
*
* @return a copy of the given geometry in the destination crs. The given geometry will not be changed!
*
* @throws UnknownCRSException DOCUMENT ME!
* @throws CRSTransformationException DOCUMENT ME!
* @throws IllegalArgumentException DOCUMENT ME!
* @throws GeometryException DOCUMENT ME!
*/
//J-
public <T extends com.vividsolutions.jts.geom.Geometry> T transformGeometry(final T geom, final String sourceCrs)
throws UnknownCRSException,
CRSTransformationException,
IllegalArgumentException,
GeometryException {
final com.vividsolutions.jts.geom.Geometry newGeom = (com.vividsolutions.jts.geom.Geometry)geom.clone();
return (T)fastTransformGeometry(newGeom, sourceCrs);
}
//J+
/**
* DOCUMENT ME!
*
* @param sourceCrs DOCUMENT ME!
* @param coords coords <T> DOCUMENT ME!
*
* @return the given geometry transformed to the destination CRS. The given geometry will be changed!
*
* @throws UnknownCRSException DOCUMENT ME!
* @throws CRSTransformationException DOCUMENT ME!
* @throws IllegalArgumentException DOCUMENT ME!
* @throws GeometryException DOCUMENT ME!
*/
//J-
public <T extends com.vividsolutions.jts.geom.Geometry> T fastTransformGeometry(final T geom,
final String sourceCrs) throws UnknownCRSException,
CRSTransformationException,
IllegalArgumentException,
GeometryException {
final String srcCrs;
if (isDefaultCrs(sourceCrs)) {
srcCrs = CismapBroker.getInstance().getDefaultCrs();
} else {
srcCrs = sourceCrs;
}
if (extractSridFromCrs(srcCrs) == 3857 && (extractSridFromCrs(destCrsAsString) == 31466 || extractSridFromCrs(destCrsAsString) == 31467)) {
// To transform a geometry from 3857 to 31466/31467, the geometry should be first transformed to an other crs
// and then to 31466/31467. Otherwise, the transformation is not correct
T ret = transformToGivenCrs(geom, "EPSG:4326");
return fastTransformGeometry(ret, "EPSG:4326");
} else {
final CoordinateSystem coordSystem = CRSFactory.create(srcCrs);
Geometry deegreeGeom = JTSAdapter.wrap(geom);
deegreeGeom = transformer.transform(deegreeGeom, coordSystem.getCRS());
final T ret = (T)JTSAdapter.export(deegreeGeom);
setSrid(ret);
return ret;
}
}
//J+
/**
* use this method carefully. If you transform the coordinates of a geometry, you should also change the SRID of the
* geomerty that contains the coordinates. That is required because the coordinates don't contain the SRID.
*
* @param sourceCrs the CRS of the given coordinates
* @param coords the coordinates to transform
*
* @return the new coordinates
*
* @throws UnknownCRSException DOCUMENT ME!
* @throws CRSTransformationException DOCUMENT ME!
* @throws IllegalArgumentException DOCUMENT ME!
* @throws GeometryException DOCUMENT ME!
*/
public com.vividsolutions.jts.geom.Coordinate[] transformGeometry(final String sourceCrs,
final com.vividsolutions.jts.geom.Coordinate... coords) throws UnknownCRSException,
CRSTransformationException,
IllegalArgumentException,
GeometryException {
final com.vividsolutions.jts.geom.GeometryFactory gfac = new com.vividsolutions.jts.geom.GeometryFactory();
com.vividsolutions.jts.geom.Geometry geom;
if (coords.length == 1) {
geom = gfac.createPoint(coords[0]);
} else {
geom = gfac.createLineString(coords);
}
geom = transformGeometry(geom, sourceCrs);
return geom.getCoordinates();
}
/**
* Set the SRID of the given Geometry object to the destination CRS of this CRSTransformer object. The coordinates
* of the geometry will not be changed.
*
* @param geom DOCUMENT ME!
*/
public void setSrid(final com.vividsolutions.jts.geom.Geometry geom) {
geom.setSRID(extractSridFromCrs(destCrsAsString));
}
/**
* transforms the given PNode object and all its sub nodes to the given CRS.
*
* @param node DOCUMENT ME!
* @param oldCrs DOCUMENT ME!
* @param newCrs DOCUMENT ME!
* @param oldWtst DOCUMENT ME!
* @param newWtst DOCUMENT ME!
*/
public static void transformPNodeToGivenCrs(final PNode node,
final String oldCrs,
final String newCrs,
final WorldToScreenTransform oldWtst,
final WorldToScreenTransform newWtst) {
final com.vividsolutions.jts.geom.GeometryFactory fac = new com.vividsolutions.jts.geom.GeometryFactory(
new PrecisionModel(PrecisionModel.FLOATING),
extractSridFromCrs(oldCrs));
final double x = oldWtst.getWorldX(node.getXOffset());
final double y = oldWtst.getWorldY(node.getYOffset());
com.vividsolutions.jts.geom.Point p = fac.createPoint(new Coordinate(x, y));
p = transformToGivenCrs(p, newCrs);
node.setOffset(newWtst.getScreenX(p.getX()), newWtst.getScreenY(p.getY()));
for (int index = 0; index < node.getChildrenCount(); ++index) {
transformPNodeToGivenCrs(node.getChild(index), oldCrs, newCrs, oldWtst, newWtst);
}
}
/**
* extracts the srid from the given srs. The srs should have the form "EPSG:XXXX"
*
* @param crs DOCUMENT ME!
*
* @return the srid or -1 if the srid could not be determined
*/
public static int extractSridFromCrs(String crs) {
try {
if (isDefaultCrs(crs)) {
crs = CismapBroker.getInstance().getDefaultCrs();
}
return Integer.parseInt(crs.substring(crs.lastIndexOf(":") + 1)); // NOI18N
} catch (final Exception e) {
LOG.error("Cannot extract the SRID from the CRS " + crs); // NOI18N
return -1;
}
}
/**
* creates the crs from the given srid.
*
* @param srid crs DOCUMENT ME!
*
* @return the crs
*/
public static String createCrsFromSrid(final int srid) {
if (isDefaultCrs("EPSG:" + srid)) {
return CismapBroker.getInstance().getDefaultCrs();
} else {
return "EPSG:" + srid;
}
}
/**
* DOCUMENT ME!
*
* @return the current srid
*/
public static int getCurrentSrid() {
return extractSridFromCrs(CismapBroker.getInstance().getSrs().getCode());
}
/**
* transforms the given geometry to the current CRS.
*
* @param <T> DOCUMENT ME!
* @param geom the geometry to transform
*
* @return the new geomerty or the given geometry, if the given geometry is already in the current CRS
*/
public static <T extends com.vividsolutions.jts.geom.Geometry> T transformToCurrentCrs(
final T geom) {
final String currentSrs = CismapBroker.getInstance().getSrs().getCode();
return transformToGivenCrs(geom, currentSrs);
}
/**
* transforms the given geometry to the given CRS.
*
* @param <T> DOCUMENT ME!
* @param geom the geometry to transform
* @param crs the target crs
*
* @return the new geomerty or the given geometry, if the given geometry is already in the right CRS
*/
public static <T extends com.vividsolutions.jts.geom.Geometry> T transformToGivenCrs(final T geom,
final String crs) {
if (geom == null) {
return null;
}
String crsname = "EPSG:" + geom.getSRID(); // NOI18N
final String defaultCrs = CismapBroker.getInstance().getDefaultCrs();
if (LOG.isDebugEnabled()) {
LOG.debug("crsname " + crsname + " given crs " + crs + " default crs: " + defaultCrs); // NOI18N
}
if (isDefaultCrs(crsname)) {
crsname = defaultCrs;
}
if (!crs.equals(crsname)) {
try {
final CrsTransformer crsTransformer = new CrsTransformer(crs);
return crsTransformer.transformGeometry(geom, crsname);
} catch (Exception e) {
LOG.error("Cannot transform the geometry from " + crsname + " to " + crs, e); // NOI18N
}
}
return geom;
}
/**
* transforms the given geometry to the default CRS.
*
* @param <T> DOCUMENT ME!
* @param geom the geometry to transform
*
* @return the new geomerty or the given geometry, if the given geometry is already in the default CRS
*/
public static <T extends com.vividsolutions.jts.geom.Geometry> T transformToDefaultCrs(final T geom) {
if (geom == null) {
return null;
}
com.vividsolutions.jts.geom.Geometry newGeom = null;
final String curCrs = "EPSG:" + geom.getSRID(); // NOI18N
// Wenn SRID nicht gesetzt oder auf -1 gesetzt ist, dann handelt es sich schon um das default CRS
if (!isDefaultCrs(curCrs)) {
try {
if (LOG.isDebugEnabled()) {
LOG.debug("transform geometry from " + curCrs + " to " // NOI18N
+ CismapBroker.getInstance().getDefaultCrs());
}
final CrsTransformer transformer = new CrsTransformer(CismapBroker.getInstance().getDefaultCrs());
newGeom = transformer.transformGeometry(geom, curCrs);
} catch (Exception e) {
LOG.error("Cannot transform the geometry from " + curCrs + " to " // NOI18N
+ CismapBroker.getInstance().getDefaultCrs(),
e);
newGeom = geom;
}
} else {
newGeom = geom;
}
return (T)newGeom;
}
/**
* transforms the given geometry to a metric CRS.
*
* @param <T> DOCUMENT ME!
* @param geom the geometry to transform
*
* @return the new geomerty or the given geometry, if the given geometry is already in the current CRS
*/
public static <T extends com.vividsolutions.jts.geom.Geometry> T transformToMetricCrs(
final T geom) {
if (geom == null) {
return null;
}
final List<Crs> crsList = CismapBroker.getInstance().getMappingComponent().getCrsList();
com.vividsolutions.jts.geom.Geometry newGeom = null;
String curCrs = "EPSG:" + geom.getSRID(); // NOI18N
if (isDefaultCrs(curCrs)) {
curCrs = CismapBroker.getInstance().getDefaultCrs();
}
final Crs curCrsObject = new Crs();
curCrsObject.setCode(curCrs);
final int index = crsList.indexOf(curCrsObject);
if (index != -1) {
final Crs crs = crsList.get(index);
if (crs.isMetric()) {
newGeom = geom;
}
}
if (newGeom == null) {
final String metricCrs = getMetricCrs().getCode();
try {
final CrsTransformer transformer = new CrsTransformer(metricCrs);
newGeom = transformer.transformGeometry(geom, curCrs);
} catch (Exception e) {
LOG.error("Cannot transform the geometry from " + curCrs + " to " + metricCrs, e); // NOI18N
newGeom = geom;
}
}
return (T)newGeom;
}
/**
* Determines a metric crs. If the default crs is metric, than this crs will be returned. Otherwise, the first
* metric crs in the crs list will be returned.
*
* @return a metric crs
*/
private static Crs getMetricCrs() {
final List<Crs> crsList = CismapBroker.getInstance().getMappingComponent().getCrsList();
Crs metricCrs = null;
for (final Crs crs : crsList) {
if (crs.isSelected() && crs.isMetric()) {
metricCrs = crs;
} else if (crs.isMetric() && (metricCrs == null)) {
metricCrs = crs;
}
}
if (metricCrs == null) {
}
return metricCrs;
}
/**
* transforms the given geometry to a metric CRS.
*
* @param <T> DOCUMENT ME!
* @param geom the geometry to transform
* @param crsList DOCUMENT ME!
*
* @return the new geomerty or the given geometry, if the given geometry is already in the current CRS
*/
public static <T extends com.vividsolutions.jts.geom.Geometry> T transformToMetricCrs(
final T geom,
final List<Crs> crsList) {
if (geom == null) {
return null;
}
com.vividsolutions.jts.geom.Geometry newGeom = null;
String curCrs = "EPSG:" + geom.getSRID(); // NOI18N
if (isDefaultCrs(curCrs)) {
curCrs = CismapBroker.getInstance().getDefaultCrs();
}
final Crs curCrsObject = new Crs();
curCrsObject.setCode(curCrs);
final int index = crsList.indexOf(curCrsObject);
if (index != -1) {
final Crs crs = crsList.get(index);
if (crs.isMetric()) {
newGeom = geom;
}
}
if (newGeom == null) {
final String metricCrs = getMetricCrs().getCode();
try {
final CrsTransformer transformer = new CrsTransformer(metricCrs);
newGeom = transformer.transformGeometry(geom, curCrs);
} catch (Exception e) {
LOG.error("Cannot transform the geometry from " + curCrs + " to " + metricCrs, e); // NOI18N
newGeom = geom;
}
}
return (T)newGeom;
}
/**
* DOCUMENT ME!
*
* @param crs DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public static boolean isDefaultCrs(final String crs) {
if (crs.endsWith(":" + CismapBroker.getInstance().getDefaultCrsAlias())
|| crs.endsWith(":0") || crs.endsWith(":-1") // NOI18N
|| crs.equals(CismapBroker.getInstance().getDefaultCrs())) {
if (crs.endsWith(":0")) {
LOG.warn("srid of a geometry is not set. This can lead to an error.", new Throwable());
}
return true;
} else {
return false;
}
}
}