ecological-engine-geospatia.../src/main/java/org/gcube/dataanalysis/geo/utils/CrsHelper.java

192 lines
7.5 KiB
Java

/*
* Copyright (c) 2009 The University of Reading
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University of Reading, nor the names of the
* authors or contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.gcube.dataanalysis.geo.utils;
import java.util.ArrayList;
import java.util.List;
import org.geotoolkit.referencing.CRS;
import org.geotoolkit.referencing.crs.DefaultGeographicCRS;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.cs.CoordinateSystemAxis;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.TransformException;
import ucar.unidata.geoloc.LatLonPoint;
import ucar.unidata.geoloc.LatLonPointImpl;
import ucar.unidata.geoloc.ProjectionPoint;
import ucar.unidata.geoloc.ProjectionPointImpl;
/**
* This class wraps the GeoTools/GeoAPI coordinate reference system methods, providing a set of convenience methods such as transformations and validity checks.
*
* @todo this object is immutable and could be re-used.
* @author Jon
*/
public final class CrsHelper {
public static final String PLATE_CARREE_CRS_CODE = "CRS:84";
public static final List<String> SUPPORTED_CRS_CODES = new ArrayList<String>();
private CoordinateReferenceSystem crs;
private MathTransform crsToLatLon;
private MathTransform latLonToCrs;
private boolean isLatLon;
static {
// Find the supported CRS codes
// I think this is the appropriate method to get all the CRS codes
// that we can support
for (Object codeObj : CRS.getSupportedCodes("urn:ogc:def")) {
SUPPORTED_CRS_CODES.add((String) codeObj);
}
System.out.println("Supported Codes:"+SUPPORTED_CRS_CODES);
}
/** Private constructor to prevent direct instantiation */
private CrsHelper() {
}
public static CrsHelper fromCrsCode(String crsCode) throws Exception {
// TODO: could cache CrsHelpers with the same code
CrsHelper crsHelper = new CrsHelper();
try {
// The "true" means "force longitude first" axis order
crsHelper.crs = CRS.decode(crsCode, true);
// Get transformations to and from lat-lon.
// The "true" means "lenient", i.e. ignore datum shifts. This
// is necessary to prevent "Bursa wolf parameters required"
// errors (Some CRSs, including British National Grid, fail if
// we are not "lenient".)
crsHelper.crsToLatLon = CRS.findMathTransform(crsHelper.crs, DefaultGeographicCRS.WGS84, true);
crsHelper.latLonToCrs = CRS.findMathTransform(DefaultGeographicCRS.WGS84, crsHelper.crs, true);
crsHelper.isLatLon = crsHelper.crsToLatLon.isIdentity();
return crsHelper;
} catch (Exception e) {
throw new Exception("Error creating CrsHelper from code " + crsCode);
}
}
public CoordinateReferenceSystem getCoordinateReferenceSystem() {
return this.crs;
}
/**
* @return true if the given coordinate pair is within the valid range of both the x and y axis of this coordinate reference system.
*/
public boolean isPointValidForCrs(ProjectionPoint point) {
return this.isPointValidForCrs(point.getX(), point.getY());
}
/**
* @return true if the given coordinate pair is within the valid range of both the x and y axis of this coordinate reference system.
*/
public boolean isPointValidForCrs(double x, double y) {
CoordinateSystemAxis xAxis = this.crs.getCoordinateSystem().getAxis(0);
CoordinateSystemAxis yAxis = this.crs.getCoordinateSystem().getAxis(1);
return x >= xAxis.getMinimumValue() && x <= xAxis.getMaximumValue() && y >= yAxis.getMinimumValue() && y <= yAxis.getMaximumValue();
}
/**
* Transforms the given x-y point in this {@link #getCoordinateReferenceSystem() CRS} to a LatLonPoint.
*
* @throws TransformException
* if the required transformation could not be performed
*/
public LatLonPoint crsToLatLon(double x, double y) throws TransformException {
if (this.isLatLon) {
// We don't need to do the transformation
return new LatLonPointImpl(y, x);
}
// We know x must go first in this array because we selected
// "force longitude-first" when creating the CRS for this grid
double[] point = new double[] { x, y };
// Transform to lat-lon in-place
this.crsToLatLon.transform(point, 0, point, 0, 1);
return new LatLonPointImpl(point[1], point[0]);
}
/**
* Transforms the given x-y point in this {@link #getCoordinateReferenceSystem() CRS} to a LatLonPoint.
*
* @throws TransformException
* if the required transformation could not be performed
*/
public LatLonPoint crsToLatLon(ProjectionPoint point) throws TransformException {
return this.crsToLatLon(point.getX(), point.getY());
}
/**
* Transforms the given LatLonPoint to an x-y point in this {@link #getCoordinateReferenceSystem() CRS}.
*
* @throws TransformException
* if the required transformation could not be performed
*/
public ProjectionPoint latLonToCrs(LatLonPoint latLonPoint) throws TransformException {
return this.latLonToCrs(latLonPoint.getLongitude(), latLonPoint.getLatitude());
}
/**
* Transforms the given longitude-latitude point to an x-y point in this {@link #getCoordinateReferenceSystem() CRS}.
*
* @throws TransformException
* if the required transformation could not be performed
*/
public ProjectionPoint latLonToCrs(double longitude, double latitude) throws TransformException {
if (this.isLatLon) {
// We don't need to do the transformation
return new ProjectionPointImpl(longitude, latitude);
}
// We know x must go first in this array because we selected
// "force longitude-first" when creating the CRS for this grid
double[] point = new double[] { longitude, latitude };
// Transform to lat-lon in-place
this.latLonToCrs.transform(point, 0, point, 0, 1);
return new ProjectionPointImpl(point[0], point[1]);
}
/**
* @return true if this crs is lat-lon
*/
public boolean isLatLon() {
return this.isLatLon;
}
public static void main(String[] args) throws Exception{
CrsHelper helper = fromCrsCode("CRS:84");
// boolean valid = helper.isPointValidForCrs(180, 0);
// System.out.println(valid);
LatLonPoint point = helper.crsToLatLon(190,10);
double x = point.getLongitude();
double y = point.getLatitude();
System.out.println(point+" ("+x+","+y+")");
}
}