Ignore:
Timestamp:
2016-01-22T16:50:40+01:00 (8 years ago)
Author:
bastiK
Message:

add 2 standard parallel & non-spherical variants for Mercator projection (see #12186)
(imports pieces of code from the Geotools project)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/data/projection/proj/Mercator.java

    r9124 r9565  
    22package org.openstreetmap.josm.data.projection.proj;
    33
    4 import static java.lang.Math.PI;
    5 import static java.lang.Math.atan;
    6 import static java.lang.Math.log;
    7 import static java.lang.Math.sinh;
    8 import static java.lang.Math.tan;
    94import static org.openstreetmap.josm.tools.I18n.tr;
    105
     
    138
    149/**
    15  * Mercator Projection.
     10 * Mercator Cylindrical Projection. The parallels and the meridians are straight lines and
     11 * cross at right angles; this projection thus produces rectangular charts. The scale is true
     12 * along the equator (by default) or along two parallels equidistant of the equator (if a scale
     13 * factor other than 1 is used). This projection is used to represent areas close to the equator.
     14 * It is also often used for maritime navigation because all the straight lines on the chart are
     15 * <em>loxodrome</em> lines, i.e. a ship following this line would keep a constant azimuth on its
     16 * compass.
     17 * <p>
     18 * This implementation handles both the 1 and 2 stardard parallel cases.
     19 * For 1 SP (EPSG code 9804), the line of contact is the equator.
     20 * For 2 SP (EPSG code 9805) lines of contact are symmetrical
     21 * about the equator.
     22 * <p>
     23 * This class has been derived from the implementation of the Geotools project;
     24 * git 8cbf52d, org.geotools.referencing.operation.projection.CassiniSoldner
     25 * at the time of migration.
     26 * <p>
     27 * <b>References:</b>
     28 * <ul>
     29 *   <li>John P. Snyder (Map Projections - A Working Manual,<br>
     30 *       U.S. Geological Survey Professional Paper 1395, 1987)</li>
     31 *   <li>"Coordinate Conversions and Transformations including Formulas",<br>
     32 *       EPSG Guidence Note Number 7, Version 19.</li>
     33 * </ul>
     34 *
     35 * @see <A HREF="http://mathworld.wolfram.com/MercatorProjection.html">Mercator projection on MathWorld</A>
     36 * @see <A HREF="http://www.remotesensing.org/geotiff/proj_list/mercator_1sp.html">"mercator_1sp" on RemoteSensing.org</A>
     37 * @see <A HREF="http://www.remotesensing.org/geotiff/proj_list/mercator_2sp.html">"mercator_2sp" on RemoteSensing.org</A>
     38 *
     39 * @author André Gosselin
     40 * @author Martin Desruisseaux (PMO, IRD)
     41 * @author Rueben Schulz
     42 * @author Simone Giannecchini
    1643 */
    17 public class Mercator implements Proj {
     44public class Mercator extends AbstractProj implements IScaleFactorProvider {
     45    /**
     46     * Maximum difference allowed when comparing real numbers.
     47     */
     48    private static final double EPSILON = 1E-6;
     49
     50    protected double scaleFactor;
    1851
    1952    @Override
     
    2457    @Override
    2558    public String getProj4Id() {
    26         return "josm:smerc"; // "merc" is ellipsoidal Mercator projection in PROJ.4
     59        return "merc";
    2760    }
    2861
    2962    @Override
    3063    public void initialize(ProjParameters params) throws ProjectionConfigurationException {
     64        super.initialize(params);
     65        scaleFactor = 1;
     66        if (params.lat_ts != null) {
     67            /*
     68             * scaleFactor is not a parameter in the 2 SP case and is computed from
     69             * the standard parallel.
     70             */
     71            double standardParallel = Math.toRadians(params.lat_ts);
     72            if (spherical) {
     73                scaleFactor *= Math.cos(standardParallel);
     74            }  else {
     75                scaleFactor *= msfn(Math.sin(standardParallel), Math.cos(standardParallel));
     76            }
     77        }
     78        /*
     79         * A correction that allows us to employs a latitude of origin that is not
     80         * correspondent to the equator. See Snyder and al. for reference, page 47.
     81         */
     82        if (params.lat0 != null) {
     83            final double lat0 = Math.toRadians(params.lat0);
     84            final double sinPhi = Math.sin(lat0);
     85            scaleFactor *= (Math.cos(lat0) / (Math.sqrt(1 - e2 * sinPhi * sinPhi)));
     86        }
    3187    }
    3288
    3389    @Override
    34     public double[] project(double lat_rad, double lon_rad) {
    35         return new double[] {lon_rad, log(tan(PI/4 + lat_rad/2))};
     90    public double[] project(double y, double x) {
     91        if (Math.abs(y) > (Math.PI/2 - EPSILON)) {
     92            return new double[] {0, 0}; // this is an error and should be handled somehow
     93        }
     94        if (spherical) {
     95            y = Math.log(Math.tan(Math.PI/4 + 0.5*y));
     96        } else {
     97            y = -Math.log(tsfn(y, Math.sin(y)));
     98        }
     99        return new double[] {x, y};
    36100    }
    37101
    38102    @Override
    39     public double[] invproject(double east, double north) {
    40         return new double[] {atan(sinh(north)), east};
     103    public double[] invproject(double x, double y) {
     104        if (spherical) {
     105            y = Math.PI/2 - 2.0*Math.atan(Math.exp(-y));
     106        } else {
     107            y = Math.exp(-y);
     108            y = cphi2(y);
     109        }
     110        return new double[] {y, x};
    41111    }
    42112
     
    45115        return new Bounds(-89, -180, 89, 180, false);
    46116    }
     117
     118    @Override
     119    public double getScaleFactor() {
     120        return scaleFactor;
     121    }
    47122}
Note: See TracChangeset for help on using the changeset viewer.