| | 1 | //License: GPL. For details, see LICENSE file. |
| | 2 | |
| | 3 | package org.openstreetmap.josm.data.projection; |
| | 4 | |
| | 5 | import static org.openstreetmap.josm.tools.I18n.tr; |
| | 6 | |
| | 7 | import java.util.logging.Logger; |
| | 8 | |
| | 9 | import javax.swing.JOptionPane; |
| | 10 | |
| | 11 | import org.openstreetmap.josm.Main; |
| | 12 | import org.openstreetmap.josm.data.coor.EastNorth; |
| | 13 | import org.openstreetmap.josm.data.coor.LatLon; |
| | 14 | |
| | 15 | |
| | 16 | /** |
| | 17 | * Projection for the SwissGrid, see http://de.wikipedia.org/wiki/Swiss_Grid. |
| | 18 | * |
| | 19 | * Calculations are based on formula from |
| | 20 | * http://www.swisstopo.admin.ch/internet/swisstopo/en/home/topics/survey/sys/refsys/switzerland.parsysrelated1.37696.downloadList.12749.DownloadFile.tmp/ch1903wgs84en.pdf |
| | 21 | * |
| | 22 | */ |
| | 23 | public class SwissGrid implements Projection { |
| | 24 | |
| | 25 | static private Logger logger = Logger.getLogger(SwissGrid.class.getName()); |
| | 26 | private boolean doAlertOnCoordinatesOufOfRange = true; |
| | 27 | |
| | 28 | |
| | 29 | /** |
| | 30 | * replies true if if wgs is in or reasonably close to Switzerland. False otherwise. |
| | 31 | * |
| | 32 | * @param wgs lat/lon in WGS89 |
| | 33 | * @return |
| | 34 | */ |
| | 35 | protected boolean latlonInAcceptableRange(LatLon wgs) { |
| | 36 | |
| | 37 | // coordinate transformation is invoked for boundary values regardless |
| | 38 | // of current data set. |
| | 39 | // |
| | 40 | if (Math.abs(wgs.lon()) == Projection.MAX_LON && Math.abs(wgs.lat()) == Projection.MAX_LAT) { |
| | 41 | return true; |
| | 42 | } |
| | 43 | return wgs.lon() >= 5.7 && wgs.lon() <= 10.6 |
| | 44 | && wgs.lat() >= 45.7 && wgs.lat() <= 47.9; |
| | 45 | } |
| | 46 | |
| | 47 | /** |
| | 48 | * displays an alert if lat/lon are not reasonably close to Switzerland. |
| | 49 | */ |
| | 50 | protected void alertCoordinatesOutOfRange() { |
| | 51 | JOptionPane.showMessageDialog(Main.parent, |
| | 52 | tr("The projection \"{0}\" is designed for\n" |
| | 53 | + "latitudes between 45.7' and 47.9'\n" |
| | 54 | + "and longitutes between 5.7' and 10.6' only.\n" |
| | 55 | + "Use another projection system if you are not working\n" |
| | 56 | + "on a data set of Switzerland or Lichtenstein.\n" |
| | 57 | + "Do not upload any data after this message.", this.toString()), |
| | 58 | "Current projection not suitable", |
| | 59 | JOptionPane.WARNING_MESSAGE |
| | 60 | ); |
| | 61 | doAlertOnCoordinatesOufOfRange = false; |
| | 62 | } |
| | 63 | |
| | 64 | /** |
| | 65 | * @param wgs WGS84 lat/lon (ellipsoid GRS80) (in degree) |
| | 66 | * @return eastnorth projection in Swiss National Grid (ellipsoid Bessel) |
| | 67 | */ |
| | 68 | public EastNorth latlon2eastNorth(LatLon wgs) { |
| | 69 | |
| | 70 | |
| | 71 | if (!latlonInAcceptableRange(wgs)) { |
| | 72 | if (doAlertOnCoordinatesOufOfRange) { |
| | 73 | alertCoordinatesOutOfRange(); |
| | 74 | } |
| | 75 | logger.warning("lat/lon out of range for SwissGrid: lat/lon=" + wgs); |
| | 76 | } |
| | 77 | |
| | 78 | double phi = 3600d * wgs.lat(); |
| | 79 | double lambda = 3600d * wgs.lon(); |
| | 80 | |
| | 81 | double phiprime = (phi - 169028.66d) / 10000d; |
| | 82 | double lambdaprime = (lambda - 26782.5d) / 10000d; |
| | 83 | |
| | 84 | // precompute squares for lambdaprime and phiprime |
| | 85 | // |
| | 86 | double lambdaprime_2 = Math.pow(lambdaprime,2); |
| | 87 | double phiprime_2 = Math.pow(phiprime,2); |
| | 88 | |
| | 89 | |
| | 90 | double north = |
| | 91 | 200147.07d |
| | 92 | + 308807.95d * phiprime |
| | 93 | + 3745.25d * lambdaprime_2 |
| | 94 | + 76.63d * phiprime_2 |
| | 95 | - 194.56d * lambdaprime_2 * phiprime |
| | 96 | + 119.79d * Math.pow(phiprime,3); |
| | 97 | |
| | 98 | |
| | 99 | double east = |
| | 100 | 600072.37d |
| | 101 | + 211455.93d * lambdaprime |
| | 102 | - 10938.51d * lambdaprime * phiprime |
| | 103 | - 0.36d * lambdaprime * phiprime_2 |
| | 104 | - 44.54d * Math.pow(lambdaprime,3); |
| | 105 | |
| | 106 | return new EastNorth(east, north); |
| | 107 | } |
| | 108 | |
| | 109 | |
| | 110 | /** |
| | 111 | * @param xy SwissGrid east/north (in meters) |
| | 112 | * @return LatLon WGS84 (in degree) |
| | 113 | */ |
| | 114 | |
| | 115 | public LatLon eastNorth2latlon(EastNorth xy) { |
| | 116 | |
| | 117 | double yp = (xy.east() - 600000d) / 1000000d; |
| | 118 | double xp = (xy.north() - 200000d) / 1000000d; |
| | 119 | |
| | 120 | // precompute squares of xp and yp |
| | 121 | // |
| | 122 | double xp_2 = Math.pow(xp,2); |
| | 123 | double yp_2 = Math.pow(yp,2); |
| | 124 | |
| | 125 | |
| | 126 | // lambda = latitude, phi = longitude |
| | 127 | double lmbp = 2.6779094d |
| | 128 | + 4.728982d * yp |
| | 129 | + 0.791484d * yp * xp |
| | 130 | + 0.1306d * yp * xp_2 |
| | 131 | - 0.0436d * Math.pow(yp,3); |
| | 132 | |
| | 133 | double phip = 16.9023892d |
| | 134 | + 3.238272d * xp |
| | 135 | - 0.270978d * yp_2 |
| | 136 | - 0.002528d * xp_2 |
| | 137 | - 0.0447d * yp_2 * xp |
| | 138 | - 0.0140d * Math.pow(xp,3); |
| | 139 | |
| | 140 | |
| | 141 | |
| | 142 | double lmb = lmbp * 100.0d / 36.0d; |
| | 143 | double phi = phip * 100.0d / 36.0d; |
| | 144 | |
| | 145 | |
| | 146 | return new LatLon(phi,lmb); |
| | 147 | |
| | 148 | } |
| | 149 | |
| | 150 | public double scaleFactor() { |
| | 151 | return 1.0; |
| | 152 | } |
| | 153 | |
| | 154 | @Override public String toString() { |
| | 155 | return tr("Swiss Grid (Switzerland)"); |
| | 156 | } |
| | 157 | |
| | 158 | public String toCode() { |
| | 159 | return "EPSG:21781"; |
| | 160 | } |
| | 161 | |
| | 162 | public String getCacheDirectoryName() { |
| | 163 | return "swissgrid"; |
| | 164 | } |
| | 165 | |
| | 166 | |
| | 167 | @Override |
| | 168 | public boolean equals(Object o) { |
| | 169 | return o instanceof SwissGrid; |
| | 170 | } |
| | 171 | |
| | 172 | @Override |
| | 173 | public int hashCode() { |
| | 174 | return SwissGrid.class.hashCode(); |
| | 175 | } |
| | 176 | |
| | 177 | } |