All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.cts.op.projection.Krovak Maven / Gradle / Ivy

Go to download

Coordinate Transformation Suite (abridged CTS) is a library developed to perform coordinate transformations using well known geodetic algorithms and parameter sets. It strives to be simple, flexible and interoperable, in this order.

There is a newer version: 1.X.X
Show newest version
/*
 * Coordinate Transformations Suite (abridged CTS)  is a library developped to 
 * perform Coordinate Transformations using well known geodetic algorithms 
 * and parameter sets. 
 * Its main focus are simplicity, flexibility, interoperability, in this order.
 *
 * This library has been originally developed by Michaël Michaud under the JGeod
 * name. It has been renamed CTS in 2009 and shared to the community from 
 * the OrbisGIS code repository.
 *
 * CTS 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 3 of the License.
 *
 * CTS 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
 * CTS. If not, see .
 *
 * For more information, please consult: 
 */
package org.cts.op.projection;

import java.util.Map;

import org.cts.CoordinateDimensionException;
import org.cts.Identifier;
import org.cts.datum.Ellipsoid;
import org.cts.op.NonInvertibleOperationException;
import org.cts.units.Measure;

import static java.lang.Math.asin;
import static java.lang.Math.atan;
import static java.lang.Math.atan2;
import static java.lang.Math.cos;
import static java.lang.Math.PI;
import static java.lang.Math.pow;
import static java.lang.Math.sin;
import static java.lang.Math.sqrt;
import static java.lang.Math.tan;

/**
 * The Krovak (North Orientated) Projection (KROVAK). 

* * @author Jules Party */ public class Krovak extends Projection { /** * The Identifier used for all Krovak projections. */ public static final Identifier KROVAK = new Identifier("EPSG", "1041", "Krovak (North Orientated)", "KROVAK"); protected final double lon0, // the reference longitude (from the datum prime meridian) FE, // false easting FN, // false northing alphac, // rotation in plane of meridian of origin of the conformal coordinates latp, // latitude of pseudo-standard parallel B, // a constant of the projection t0, // a constant of the projection n, // a constant of the projection r0; // a constant of the projection /** * Create a new Krovak (North Orientated) Projection corresponding to the * Ellipsoid and the list of parameters given in argument and * initialize common parameters lon0, FE, FN and other useful parameters. * * @param ellipsoid ellipsoid used to define the projection. * @param parameters a map of useful parameters to define the projection. */ public Krovak(final Ellipsoid ellipsoid, final Map parameters) { super(KROVAK, ellipsoid, parameters); lon0 = getCentralMeridian(); double lat0 = getLatitudeOfOrigin(); FE = getFalseEasting(); FN = getFalseNorthing(); alphac = getAzimuth(); double kp = getScaleFactor(); latp = 78.5 * PI / 180; double a = ellipsoid.getSemiMajorAxis(); double e2 = ellipsoid.getSquareEccentricity(); double e = ellipsoid.getEccentricity(); double sin0 = sin(lat0); double A = a * sqrt(1 - e2) / (1 - e2 * sin0 * sin0); B = sqrt(1 + e2 / (1 - e2) * pow(cos(lat0), 4)); double gamma0 = asin(sin0 / B); t0 = tan((PI / 2 + gamma0) / 2) * pow(pow((1 + e * sin0) / (1 - e * sin0), e / 2) / tan((PI / 2 + lat0) / 2), B); n = sin(latp); r0 = kp * A / tan(latp); } /** * Return the * Surface type of this * Projection. */ @Override public Surface getSurface() { return Projection.Surface.CONICAL; } /** * Return the * Property of this * Projection. */ @Override public Property getProperty() { return Projection.Property.CONFORMAL; } /** * Return the * Orientation of this * Projection. */ @Override public Orientation getOrientation() { return Projection.Orientation.SECANT; } /** * Transform coord using the Krovak (North Orientated) Projection. Input * coord is supposed to be a geographic latitude / longitude coordinate in * radians. Algorithm based on the OGP's Guidance Note Number 7 Part 2 : * * * @param coord coordinate to transform * @throws CoordinateDimensionException if coord length is not * compatible with this CoordinateOperation. */ @Override public double[] transform(double[] coord) throws CoordinateDimensionException { double lat = coord[0]; double lon = coord[1]; double e = ellipsoid.getEccentricity(); double esin = e * sin(lat); double U = 2 * (atan(t0 * pow(tan((PI / 2 + lat) / 2) / pow((1 + esin) / (1 - esin), e / 2), B)) - PI / 4); double V = B * (lon0 - lon); double T = asin(cos(alphac) * sin(U) + sin(alphac) * cos(U) * cos(V)); double sinD = cos(U) * sin(V) / cos(T); double cosD = (cos(alphac) * sin(T) - sin(U)) / sin(alphac) / cos(T); double D = atan2(sinD, cosD); double theta = n * D; double r = r0 * pow(tan((latp + PI / 2) / 2) / tan((T + PI / 2) / 2), n); coord[0] = FE - r * sin(theta); coord[1] = FN - r * cos(theta); return coord; } /** * Creates the inverse operation for Krovak (North Orientated) Projection. * Input coord is supposed to be a projected easting / northing coordinate * in meters. Algorithm based on the OGP's Guidance Note Number 7 Part 2 : * */ @Override public Projection inverse() throws NonInvertibleOperationException { return new Krovak(ellipsoid, parameters) { @Override public double[] transform(double[] coord) throws CoordinateDimensionException { double Xp = -coord[1] + FN; double Yp = -coord[0] + FE; double r = sqrt(Xp * Xp + Yp * Yp); double theta = atan(Yp / Xp); double D = theta / sin(latp); double T = 2 * (atan(pow(r0 / r, 1 / n) * tan((latp + PI / 2) / 2)) - PI / 4); double U = asin(cos(alphac) * sin(T) - sin(alphac) * cos(T) * cos(D)); double V = asin(cos(T) * sin(D) / cos(U)); double oldLat = 1E30; double lat = U; final int MAXITER = 10; double e = ellipsoid.getEccentricity(); int iter = 0; while (++iter < MAXITER && Math.abs(lat - oldLat) > 1E-15) { oldLat = lat; lat = 2 * (atan(pow(tan((U + PI / 2) / 2) / t0, 1 / B) * pow((1 + e * sin(lat)) / (1 - e * sin(lat)), e / 2)) - PI / 4); } if (iter == MAXITER) { throw new ArithmeticException("The inverse method diverges"); } double lon = lon0 - V / B; coord[0] = lat; coord[1] = lon; return coord; } @Override public Projection inverse() throws NonInvertibleOperationException { return Krovak.this; } @Override public boolean isDirect() { return false; } @Override public String toString() { return Krovak.this.toString() + " inverse"; } }; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy