001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.data.projection; 003 004import org.openstreetmap.josm.data.coor.EastNorth; 005import org.openstreetmap.josm.data.coor.LatLon; 006import org.openstreetmap.josm.data.projection.datum.Datum; 007import org.openstreetmap.josm.data.projection.proj.Proj; 008 009/** 010 * Implementation of the Projection interface that represents a coordinate reference system and delegates 011 * the real projection and datum conversion to other classes. 012 * 013 * It handles false easting and northing, central meridian and general scale factor before calling the 014 * delegate projection. 015 * 016 * Forwards lat/lon values to the real projection in units of radians. 017 * 018 * The fields are named after Proj.4 parameters. 019 * 020 * Subclasses of AbstractProjection must set ellps and proj to a non-null value. 021 * In addition, either datum or nadgrid has to be initialized to some value. 022 */ 023public abstract class AbstractProjection implements Projection { 024 025 protected Ellipsoid ellps; 026 protected Datum datum; 027 protected Proj proj; 028 protected double x_0 = 0.0; /* false easting (in meters) */ 029 protected double y_0 = 0.0; /* false northing (in meters) */ 030 protected double lon_0 = 0.0; /* central meridian */ 031 protected double k_0 = 1.0; /* general scale factor */ 032 033 public final Ellipsoid getEllipsoid() { 034 return ellps; 035 } 036 037 public final Datum getDatum() { 038 return datum; 039 } 040 041 /** 042 * Replies the projection (in the narrow sense) 043 * @return The projection object 044 */ 045 public final Proj getProj() { 046 return proj; 047 } 048 049 public final double getFalseEasting() { 050 return x_0; 051 } 052 053 public final double getFalseNorthing() { 054 return y_0; 055 } 056 057 public final double getCentralMeridian() { 058 return lon_0; 059 } 060 061 public final double getScaleFactor() { 062 return k_0; 063 } 064 065 @Override 066 public EastNorth latlon2eastNorth(LatLon ll) { 067 ll = datum.fromWGS84(ll); 068 double[] en = proj.project(Math.toRadians(ll.lat()), Math.toRadians(ll.lon() - lon_0)); 069 return new EastNorth(ellps.a * k_0 * en[0] + x_0, ellps.a * k_0 * en[1] + y_0); 070 } 071 072 @Override 073 public LatLon eastNorth2latlon(EastNorth en) { 074 double[] latlon_rad = proj.invproject((en.east() - x_0) / ellps.a / k_0, (en.north() - y_0) / ellps.a / k_0); 075 LatLon ll = new LatLon(Math.toDegrees(latlon_rad[0]), Math.toDegrees(latlon_rad[1]) + lon_0); 076 return datum.toWGS84(ll); 077 } 078 079 @Override 080 public double getDefaultZoomInPPD() { 081 // this will set the map scaler to about 1000 m 082 return 10; 083 } 084 085 /** 086 * @return The EPSG Code of this CRS, null if it doesn't have one. 087 */ 088 public abstract Integer getEpsgCode(); 089 090 /** 091 * Default implementation of toCode(). 092 * Should be overridden, if there is no EPSG code for this CRS. 093 */ 094 @Override 095 public String toCode() { 096 return "EPSG:" + getEpsgCode(); 097 } 098 099 protected static final double convertMinuteSecond(double minute, double second) { 100 return (minute/60.0) + (second/3600.0); 101 } 102 103 protected static final double convertDegreeMinuteSecond(double degree, double minute, double second) { 104 return degree + (minute/60.0) + (second/3600.0); 105 } 106}