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

org.cts.op.projection.Polyconic 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.cos;
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 Polyconic (American) Projection (POLY). 

* * @author Jules Party */ public class Polyconic extends Projection { /** * The Identifier used for all Polyconic projections. */ public static final Identifier POLY = new Identifier("EPSG", "9818", "Polyconic (American)", "POLY"); protected final double lat0, // the reference latitude lon0, // the reference longitude (from the datum prime meridian) FE, // false easting FN; // false northing /** * Create a new Polyconic Projection corresponding to the * Ellipsoid and the list of parameters given in argument and * initialize common parameters lon0, lat0, FE, FN. * * @param ellipsoid ellipsoid used to define the projection. * @param parameters a map of useful parameters to define the projection. */ public Polyconic(final Ellipsoid ellipsoid, final Map parameters) { super(POLY, ellipsoid, parameters); lon0 = getCentralMeridian(); lat0 = getLatitudeOfOrigin(); FE = getFalseEasting(); FN = getFalseNorthing(); } /** * Return the * Surface type of this * Projection. */ @Override public Surface getSurface() { return Projection.Surface.PSEUDOCONICAL; } /** * Return the * Property of this * Projection. */ @Override public Property getProperty() { return Projection.Property.APHYLACTIC; } /** * Return the * Orientation of this * Projection. */ @Override public Orientation getOrientation() { return Projection.Orientation.TANGENT; } /** * Transform coord using the Polyconic Projection. Input coord is supposed * to be a geographic latitude / longitude coordinate in radians. Algorithm * based on the USGS professional paper 1395, "Map Projection - A Working * Manual" by John P. Snyder : * * * @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 a = ellipsoid.getSemiMajorAxis(); double M0 = a * ellipsoid.curvilinearAbscissa(lat0); if (coord[0] == 0) { coord[0] = FE + ellipsoid.getSemiMajorAxis() * (coord[1] - lon0); coord[1] = FN - M0; } else { double M = a * ellipsoid.curvilinearAbscissa(coord[0]); double v = ellipsoid.transverseRadiusOfCurvature(coord[0]); double L = (coord[1] - lon0) * sin(coord[0]); coord[1] = FN + M - M0 + v / tan(coord[0]) * (1 - cos(L)); coord[0] = FE + v / tan(coord[0]) * sin(L); } return coord; } private double curvilinearAbscissaPrime(double latitude) { double[] arc_coeff = ellipsoid.getArcCoeff(); return arc_coeff[0] + 2 * arc_coeff[1] * cos(2 * latitude) + 4 * arc_coeff[2] * cos(4 * latitude) + 6 * arc_coeff[3] * cos(6 * latitude) + 8 * arc_coeff[4] * cos(8 * latitude); } /** * Creates the inverse operation for Polyconic Projection. Input coord is * supposed to be a projected easting / northing coordinate in meters. * Algorithm based on the USGS professional paper 1395, "Map Projection - A * Working Manual" by John P. Snyder : * */ @Override public Projection inverse() throws NonInvertibleOperationException { return new Polyconic(ellipsoid, parameters) { @Override public double[] transform(double[] coord) throws CoordinateDimensionException { double a = ellipsoid.getSemiMajorAxis(); double M0 = a * ellipsoid.curvilinearAbscissa(lat0); double e2 = ellipsoid.getSquareEccentricity(); double x = coord[0] - FE; double y = coord[1] - FN; if (y + M0 == 0) { coord[0] = 0; coord[1] = lon0 + x / a; } else { double A = (y + M0) / a; double B = A * A + pow(x / a, 2); double C = 0; final int MAXITER = 10; double lat = A, latold = 1.E30; int iter = 0; while (++iter < MAXITER && Math.abs(lat - latold) > 1.E-15) { latold = lat; C = sqrt(1 - e2 * sin(lat) * sin(lat)) * tan(lat); double J = ellipsoid.curvilinearAbscissa(lat); double I = curvilinearAbscissaPrime(lat); lat = latold - (A * (C * J + 1) - J - C / 2 * (J * J + B)) / (e2 * sin(2 * latold) * (J * (J - 2 * A) + B) / 4 / C + (A - J) * (C * I - 2 / sin(2 * latold)) - I); } if (iter == MAXITER) { throw new ArithmeticException("The inverse Polyconic Projection method diverges. Last value of tolerance = " + Math.abs(lat - latold)); } coord[0] = lat; coord[1] = lon0 + asin(x * C / a) / sin(lat); } return coord; } @Override public Projection inverse() throws NonInvertibleOperationException { return Polyconic.this; } @Override public boolean isDirect() { return false; } @Override public String toString() { return Polyconic.this.toString() + " inverse"; } }; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy