Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (C) 2013-2019 52°North Initiative for Geospatial Open Source
* Software GmbH
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*
* If the program is linked with libraries which are licensed under one of
* the following licenses, the combination of the program with the linked
* library is not considered a "derivative work" of the program:
*
* - Apache License, version 2.0
* - Apache Software License, version 1.0
* - GNU Lesser General Public License, version 3
* - Mozilla Public License, versions 1.0, 1.1 and 2.0
* - Common Development and Distribution License (CDDL), version 1.0
*
* Therefore the distribution of the program linked with libraries licensed
* under the aforementioned licenses, is permitted by the copyright holders
* if the distribution is compliant with both the GNU General Public License
* version 2 and the aforementioned licenses.
*
* This program 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 General Public License
* for more details.
*/
package org.n52.io.crs;
import org.geotools.factory.Hints;
import org.geotools.geometry.jts.JTS;
import org.geotools.referencing.CRS;
import org.geotools.referencing.CRS.AxisOrder;
import org.geotools.referencing.ReferencingFactoryFinder;
import org.n52.io.geojson.old.GeojsonCrs;
import org.n52.io.geojson.old.GeojsonPoint;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.crs.CRSAuthorityFactory;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.TransformException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.PrecisionModel;
import com.vividsolutions.jts.io.ParseException;
import com.vividsolutions.jts.io.WKTReader;
public final class CRSUtils {
public static final int EPSG_WGS84 = 4326;
/**
* Default is CRS:84 (EPSG:4326 with lon/lat ordering).
*/
public static final String DEFAULT_CRS = "CRS:84";
private static final Logger LOGGER = LoggerFactory.getLogger(CRSUtils.class);
private static final String EPSG_PREFIX = "EPSG:";
/**
* Internally used spatial reference frame.
*/
private static CoordinateReferenceSystem internCrs;
protected CRSAuthorityFactory crsFactory;
/**
* use static constructors to create an instance.
*
* @param crsFactory a factory used to create authorized reference systems.
* @throws IllegalStateException if creating {@link #internCrs} fails.
*/
private CRSUtils(CRSAuthorityFactory crsFactory) {
try {
internCrs = CRS.decode(DEFAULT_CRS);
this.crsFactory = crsFactory;
} catch (FactoryException e) {
throw new IllegalStateException("Could not create intern CRS!", e);
}
}
public Point convertToPointFrom(GeojsonPoint geometry) {
return convertToPointFrom(geometry, DEFAULT_CRS);
}
public Point convertToPointFrom(GeojsonPoint geometry, String crs) {
Double[] coordinates = geometry.getCoordinates();
return createPoint(coordinates[0], coordinates[1], crs);
}
/**
* Creates a GeoJSON representation for the given point.
*
* @param point the point to convert.
* @return a GeoJSON representation of the given point.
*/
public GeojsonPoint convertToGeojsonFrom(Point point) {
Coordinate coords = point.getCoordinate();
if (point.getDimension() == 2) {
return GeojsonPoint.createWithCoordinates(new Double[] {coords.x,
coords.y});
} else {
return GeojsonPoint.createWithCoordinates(new Double[] {coords.x,
coords.y,
coords.z});
}
}
/**
* Creates a GeoJSON representation of the given point. Adds a named crs member if
* it is different to the internally used CRS:84.
*
* @param point the point to be converted to GeoJSON.
* @param targetCrs the target CRS.
* @return a GeoJSON representation of the given point.
* @throws TransformException if transforming point fails.
* @throws FactoryException if creating the target CRS fails.
*/
public GeojsonPoint convertToGeojsonFrom(Point point, String targetCrs)
throws TransformException, FactoryException {
Point transformedPoint = (Point) transformInnerToOuter(point, targetCrs);
GeojsonPoint asGeoJSON = convertToGeojsonFrom(transformedPoint);
if (!DEFAULT_CRS.equalsIgnoreCase(targetCrs)) {
asGeoJSON.setCrs(GeojsonCrs.createNamedCRS(targetCrs));
}
return asGeoJSON;
}
/**
* Creates a 2D point geometry within the given reference system.
*
* @param x the coordinate's x value.
* @param y the coordinate's y value.
* @param srs an authoritive spatial reference system code, e.g. EPSG:4326 or
* CRS:84 .
* @return a point referenced by the given spatial reference system.
*/
public Point createPoint(Double x, Double y, String srs) {
return createPoint(x, y, null, srs);
}
/**
* Creates a 2D point geometry with respect to its height and given reference system.
*
* @param x the point's x value.
* @param y the point's y value.
* @param z the height or null or NaN if coordinate is 2D.
* @param srs an authoritive spatial reference system code, e.g. EPSG:4326 or
* CRS:84 .
* @return a point referenced by the given spatial reference system.
*/
public Point createPoint(Double x, Double y, Double z, String srs) {
Coordinate coordinate = z != null && !z.isNaN()
? new Coordinate(x, y, z)
: new Coordinate(x, y);
GeometryFactory factory = createGeometryFactory(srs);
return factory.createPoint(coordinate);
}
public Geometry createLineString(Coordinate[] coordinates, String srs) {
GeometryFactory factory = createGeometryFactory(srs);
return factory.createLineString(coordinates);
}
public GeometryFactory createGeometryFactory() {
return createGeometryFactory(DEFAULT_CRS);
}
public GeometryFactory createGeometryFactory(String srsId) {
PrecisionModel pm = new PrecisionModel(PrecisionModel.FLOATING);
return srsId == null
? new GeometryFactory(pm)
: new GeometryFactory(pm, getSrsIdFrom(srsId));
}
/**
* Extracts the SRS number of the incoming SRS definition string. This can be either an HTTP URL
* (like http://www.opengis.net/def/crs/EPSG/0/4326) or a URN (like
* urn:ogc:def:crs:EPSG::31466).
*
* @param srs the SRS definition string, either as URL ('/'-separated) or as URN
* (': '-separated).
* @return the SRS number, e.g. 4326
*/
public int getSrsIdFrom(String srs) {
return getSrsIdFromEPSG(extractSRSCode(srs));
}
/**
* @param srs the SRS definition string, either as URL ('/'-separated) or as URN
* (': '-separated).
* @return SRS string in the form of for example 'EPSG:4326' or 'EPSG:31466'.
*/
public String extractSRSCode(String srs) {
if (isSrsUrlDefinition(srs)) {
return EPSG_PREFIX + srs.substring(srs.lastIndexOf("/") + 1);
} else {
String[] srsParts = srs.split(":");
return EPSG_PREFIX + srsParts[srsParts.length - 1];
}
}
private boolean isSrsUrlDefinition(String srs) {
return srs.startsWith("http");
}
public int getSrsIdFromEPSG(String srs) {
String[] epsgParts = srs.split(":");
if (epsgParts.length > 1) {
return Integer.parseInt(epsgParts[epsgParts.length - 1]);
}
return Integer.parseInt(srs);
}
/**
* Transforms a given geometry from a given reference to inner reference, which is WGS84
* (CRS:84).
*
* @param geometry the geometry to transform.
* @param srcFrame the CRS authority code the given point is referenced in.
* @return a geometry referenced in WGS84
* @throws FactoryException if the creation of {@link CoordinateReferenceSystem} fails or no
* appropriate {@link MathTransform} could be created.
* @throws TransformException if transformation fails for any other reason.
*/
public Geometry transformOuterToInner(Geometry geometry, String srcFrame)
throws FactoryException, TransformException {
return transform(geometry, getCrsFor(srcFrame), internCrs);
}
/**
* Transforms a given geometry from its inner reference (which is WGS84 (CRS:84)) to a given
* reference.
*
* @param geometry the geometry to transform.
* @param destFrame the CRS authority code the given point shall be transformed to.
* @return a transformed geometry with dest reference.
* @throws FactoryException if the creation of {@link CoordinateReferenceSystem} fails or no
* appropriate {@link MathTransform} could be created.
* @throws TransformException if transformation fails for any other reason.
*/
public Geometry transformInnerToOuter(Geometry geometry, String destFrame)
throws FactoryException, TransformException {
return transform(geometry, internCrs, getCrsFor(destFrame));
}
/**
* Transforms a given geometry from a given reference to a destinated reference.
*
* @param geometry the geometry to transform.
* @param srcFrame the reference the given point is in.
* @param destFrame the reference frame the point shall be transformed to.
* @return a transformed point.
* @throws FactoryException if the creation of {@link CoordinateReferenceSystem} fails or no
* appropriate {@link MathTransform} could be created.
* @throws TransformException if transformation fails for any other reason.
*/
public Geometry transform(Geometry geometry, String srcFrame, String destFrame)
throws FactoryException, TransformException {
return transform(geometry, getCrsFor(srcFrame), getCrsFor(destFrame));
}
private Geometry transform(Geometry geometry, CoordinateReferenceSystem srs,
CoordinateReferenceSystem dest) throws FactoryException, TransformException {
return JTS.transform(geometry, CRS.findMathTransform(srs, dest));
}
public Geometry parseWkt(String wkt) {
try {
return new WKTReader().read(wkt);
} catch (ParseException e) {
LOGGER.error("Invalid WKT '{}'", wkt, e);
return null;
}
}
/**
* Indicates if the given reference frame has switched axes compared to the inner default
* (lon/lat).
*
* @param outer the given reference frame code to check.
* @return true if axes order is switched compared to the inner default.
* @throws FactoryException if no proper CRS could be created.
*/
public boolean isLatLonAxesOrder(String outer) throws FactoryException {
return isAxesSwitched(internCrs, getCrsFor(outer));
}
/**
* Gets the propert coordinate reference system defined for the given authority code. If no
* matching CRS could be found the default {@link #internCrs} is being returned.
*
* @param authorityCode the CRS code, like EPSG:4326 or CRS:84.
* @return the CRS instance for the given code or {@link #internCrs} if either no matching CRS
* could be found or an error occured during resolving code.
* @throws FactoryException if creating CRS failed.
*/
private CoordinateReferenceSystem getCrsFor(String authorityCode) throws
FactoryException {
if (authorityCode == null || DEFAULT_CRS.equalsIgnoreCase(authorityCode)) {
return internCrs;
}
return crsFactory.createCoordinateReferenceSystem(authorityCode);
}
/**
* @param first the first CRS.
* @param second the second CRS.
* @return true if the first axes of both given CRS do not point in the same
* direction, false otherwise.
*/
private boolean isAxesSwitched(CoordinateReferenceSystem first,
CoordinateReferenceSystem second) {
AxisOrder axisOrderFirst = CRS.getAxisOrder(first);
AxisOrder axisOrderSecond = CRS.getAxisOrder(second);
if (axisOrderFirst == AxisOrder.INAPPLICABLE
|| axisOrderSecond == AxisOrder.INAPPLICABLE) {
LOGGER.warn("Could not determine if axes ordering is switched.");
return false;
}
return axisOrderFirst != axisOrderSecond;
}
/**
* Creates an {@link CRSUtils} which offers assistance when doing spatial opererations. Strict
* means that all CRS defined with lat/lon axis ordering will be handled as defined.
*
* @return creates a reference helper which (strictly) handles referencing operations.
* @throws IllegalStateException if decoding default CRS fails.
*/
public static CRSUtils createEpsgStrictAxisOrder() {
/*
* Setting FORCE_LONGITUDE_FIRST_AXIS_ORDER to FALSE seems to be unnecessary as this is geotools
* default value for this. It becomes necessary, when property org.geotools.referencing.forceXY was
* set as System property which silently switches axis order when running in the same JVM environment
* (as within an Apache Tomcat).
*
* FORCE_LONGITUDE_FIRST_AXIS_ORDER parameter is preferred to org.geotools.referencing.forceXY so we
* have to set it explicitly to find the correct CRS factory.
*/
Hints hints = new Hints(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, false);
return createEpsgReferenceHelper(hints);
}
/**
* Creates a {@link CRSUtils} which offers assistance when doing spatial opererations. Forcing
* XY means that CRS axis ordering is considered lon/lat ordering, even if defined lat/lon.
*
* @return creates a reference helper which (strictly) handles referencing operations.
* @throws IllegalStateException if decoding default CRS fails.
*/
public static CRSUtils createEpsgForcedXYAxisOrder() {
Hints hints = new Hints(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, true);
return createEpsgReferenceHelper(hints);
}
/**
* Creates a {@link CRSUtils} which offers assistance when doing spatial opererations.
*
* @param hints Some Geotools {@link Hints} which set behavior and special considerations
* regarding to the spatial operations.
* @return an instance of {@link CRSUtils} using given hints
*/
public static CRSUtils createEpsgReferenceHelper(Hints hints) throws IllegalStateException {
return new CRSUtils(ReferencingFactoryFinder.getCRSAuthorityFactory("EPSG", hints));
}
}