Ticket #3989: projection.patch
| File projection.patch, 36.3 KB (added by , 16 years ago) |
|---|
-
GaussLaborde_Reunion.java
216 216 } 217 217 218 218 public double getDefaultZoomInPPD() { 219 // this will set the map scaler to about 1000 m 220 return 10.0 2;219 // this will set the map scaler to about 1000 m (in default scale, 1 pixel will be 10 meters) 220 return 10.0; 221 221 } 222 222 } -
Lambert.java
1 //License: GPL. For details, see LICENSE file. 2 //Thanks to Johan Montagnat and its geoconv java converter application 3 //(http://www.i3s.unice.fr/~johan/gps/ , published under GPL license) 4 //from which some code and constants have been reused here. 1 // License: GPL. For details, see LICENSE file. 5 2 package org.openstreetmap.josm.data.projection; 6 3 7 4 import static org.openstreetmap.josm.tools.I18n.tr; 8 5 9 import javax.swing.JOptionPane; 6 import java.awt.GridBagLayout; 7 import java.io.IOException; 8 import java.io.InputStream; 9 import java.util.Collection; 10 import java.util.Collections; 10 11 12 import javax.swing.JComboBox; 13 import javax.swing.JLabel; 14 import javax.swing.JPanel; 15 11 16 import org.openstreetmap.josm.Main; 12 17 import org.openstreetmap.josm.data.Bounds; 13 18 import org.openstreetmap.josm.data.coor.EastNorth; 14 19 import org.openstreetmap.josm.data.coor.LatLon; 20 import org.openstreetmap.josm.tools.GBC; 15 21 16 public class Lambert implements Projection { 22 /** 23 * This class provides the two methods <code>latlon2eastNorth</code> and <code>eastNorth2latlon</code> 24 * converting the JOSM LatLon coordinates in WGS84 system (GPS) to and from East North values in 25 * the projection Lambert conic conform 4 zones using the French geodetic system NTF. 26 * This newer version uses the grid translation NTF<->RGF93 provided by IGN for a submillimetric accuracy. 27 * (RGF93 is the French geodetic system similar to WGS84 but not mathematically equal) 28 * @author Pieren 29 */ 30 public class Lambert implements Projection, ProjectionSubPrefs { 17 31 /** 18 32 * Lambert I, II, III, and IV projection exponents 19 33 */ … … 48 62 /** 49 63 * France is divided in 4 Lambert projection zones (1,2,3 + 4th for Corsica) 50 64 */ 51 public static final double cMaxLatZone1 = Math.toRadians(57 * 0.9); 65 public static final double cMaxLatZone1Radian = Math.toRadians(57 * 0.9); 66 public static final double cMinLatZone1Radian = Math.toRadians(46.1 * 0.9);// lowest latitude of Zone 4 (South Corsica) 52 67 53 public static final double zoneLimits[] = { Math.toRadians(53.5 * 0.9), // between Zone 1 and Zone 2 (in grad *0.9) 54 Math.toRadians(50.5 * 0.9), // between Zone 2 and Zone 3 55 Math.toRadians(47.51963 * 0.9), // between Zone 3 and Zone 4 56 Math.toRadians(46.17821 * 0.9) };// lowest latitude of Zone 4 68 public static final double zoneLimitsDegree[][] = { 69 {Math.toDegrees(cMaxLatZone1Radian), (53.5 * 0.9)}, // Zone 1 (reference values in grad *0.9) 70 {(53.5 * 0.9), (50.5 * 0.9)}, // Zone 2 71 {(50.5 * 0.9), (47.0 * 0.9)}, // Zone 3 72 {(47.51963 * 0.9), Math.toDegrees(cMinLatZone1Radian)} // Zone 4 73 }; 57 74 58 public static final double cMinLonZones = Math.toRadians(-4.9074074074074059 * 0.9);75 public static final double cMinLonZonesRadian = Math.toRadians(-4.9074074074074059 * 0.9); 59 76 60 public static final double cMaxLonZones = Math.toRadians(10.2 * 0.9);77 public static final double cMaxLonZonesRadian = Math.toRadians(10.2 * 0.9); 61 78 62 79 /** 63 * Because josm cannot work correctly if two zones are displayed, we allow some overlapping80 * Allow some extension beyond the theoretical limits 64 81 */ 65 public static final double cMaxOverlappingZones = Math.toRadians(1.5 * 0.9);82 public static final double cMaxOverlappingZonesDegree = 1.5; 66 83 67 public static int layoutZone = -1;84 public static final int DEFAULT_ZONE = 0; 68 85 69 private static int currentZone = 0;86 private static int layoutZone = DEFAULT_ZONE; 70 87 88 private static NTV2GridShiftFile ntf_rgf93Grid = null; 89 90 public static NTV2GridShiftFile getNtf_rgf93Grid() { 91 return ntf_rgf93Grid; 92 } 93 94 public Lambert() { 95 if (ntf_rgf93Grid == null) { 96 try { 97 String gridFileName = "ntf_r93_b.gsb"; 98 InputStream is = Main.class.getResourceAsStream("/images/data/projection/"+gridFileName); 99 ntf_rgf93Grid = new NTV2GridShiftFile(); 100 ntf_rgf93Grid.loadGridShiftFile(is, false); 101 System.out.println("NTF<->RGF93 grid loaded."); 102 } catch (Exception e) { 103 e.printStackTrace(); 104 } 105 } 106 } 107 71 108 /** 72 109 * @param p WGS84 lat/lon (ellipsoid GRS80) (in degree) 73 110 * @return eastnorth projection in Lambert Zone (ellipsoid Clark) 111 * @throws IOException 74 112 */ 75 113 public EastNorth latlon2eastNorth(LatLon p) { 76 114 // translate ellipsoid GRS80 (WGS83) => Clark 77 LatLon geo = GRS802Clark(p);78 double lt = geo.lat(); // in radian79 double lg = geo.lon();115 LatLon geo = WGS84_to_NTF(p); 116 double lt = Math.toRadians(geo.lat()); // in radian 117 double lg = Math.toRadians(geo.lon()); 80 118 81 119 // check if longitude and latitude are inside the French Lambert zones 82 currentZone = 0; 83 boolean outOfLambertZones = false; 84 if (lt >= zoneLimits[3] && lt <= cMaxLatZone1 && lg >= cMinLonZones && lg <= cMaxLonZones) { 85 // zone I 86 if (lt > zoneLimits[0]) { 87 currentZone = 0; 88 } else if (lt > zoneLimits[1]) { 89 currentZone = 1; 90 } else if (lt > zoneLimits[2]) { 91 currentZone = 2; 92 } else if (lt > zoneLimits[3]) 93 // Note: zone IV is dedicated to Corsica island and extends from 47.8 to 94 // 45.9 degrees of latitude. There is an overlap with zone III that can be 95 // solved only with longitude (covers Corsica if lon > 7.2 degree) 96 if (lg < Math.toRadians(8 * 0.9)) { 97 currentZone = 2; 98 } else { 99 currentZone = 3; 100 } 101 } else { 102 outOfLambertZones = true; // possible when MAX_LAT is used 103 } 104 if (!outOfLambertZones) { 105 if (layoutZone == -1) { 106 layoutZone = currentZone; 107 } else if (layoutZone != currentZone) { 108 if (farawayFromLambertZoneFrance(lt,lg)) { 109 JOptionPane.showMessageDialog(Main.parent, 110 tr("IMPORTANT : data positioned far away from\n" 111 + "the current Lambert zone limits.\n" 112 + "Do not upload any data after this message.\n" 113 + "Undo your last action, save your work\n" 114 + "and start a new layer on the new zone."), 115 tr("Warning"), 116 JOptionPane.WARNING_MESSAGE); 117 layoutZone = -1; 118 } else { 119 System.out.println("temporarily extend Lambert zone " + layoutZone + " projection at lat,lon:" 120 + lt + "," + lg); 121 } 122 } 123 } 124 if (layoutZone == -1) 125 return ConicProjection(lt, lg, Xs[currentZone], Ys[currentZone], c[currentZone], n[currentZone]); 126 return ConicProjection(lt, lg, Xs[layoutZone], Ys[layoutZone], c[layoutZone], n[layoutZone]); 120 if (lt >= cMinLatZone1Radian && lt <= cMaxLatZone1Radian && lg >= cMinLonZonesRadian && lg <= cMaxLonZonesRadian) 121 return ConicProjection(lt, lg, Xs[layoutZone], Ys[layoutZone], c[layoutZone], n[layoutZone]); 122 return ConicProjection(lt, lg, Xs[0], Ys[0], c[0], n[0]); 127 123 } 128 124 129 125 public LatLon eastNorth2latlon(EastNorth p) { 130 126 LatLon geo; 131 if (layoutZone == -1) { 132 // possible until the Lambert zone is determined by latlon2eastNorth() with a valid LatLon 133 geo = Geographic(p, Xs[currentZone], Ys[currentZone], c[currentZone], n[currentZone]); 134 } else { 135 geo = Geographic(p, Xs[layoutZone], Ys[layoutZone], c[layoutZone], n[layoutZone]); 136 } 137 // translate ellipsoid Clark => GRS80 (WGS83) 138 LatLon wgs = Clark2GRS80(geo); 139 return new LatLon(Math.toDegrees(wgs.lat()), Math.toDegrees(wgs.lon())); 127 geo = Geographic(p, Xs[layoutZone], Ys[layoutZone], c[layoutZone], n[layoutZone]); 128 // translate geodetic system from NTF (ellipsoid Clark) to RGF93/WGS84 (ellipsoid GRS80) 129 return NTF_to_WGS84(geo); 140 130 } 141 131 142 132 @Override public String toString() { … … 144 134 } 145 135 146 136 public String toCode() { 147 return "EPSG:"+(27561+ currentZone);137 return "EPSG:"+(27561+layoutZone); 148 138 } 149 139 150 140 public String getCacheDirectoryName() { … … 181 171 * @param Ys false north (coordinate system origin) in meters 182 172 * @param c projection constant 183 173 * @param n projection exponent 184 * @return LatLon in radian174 * @return LatLon in degree 185 175 */ 186 176 private LatLon Geographic(EastNorth eastNorth, double Xs, double Ys, double c, double n) { 187 177 double dx = eastNorth.east() - Xs; … … 200 190 delta = Math.abs(nlt - lat); 201 191 lat = nlt; 202 192 } 203 return new LatLon( lat, lon); // in radian193 return new LatLon(Math.toDegrees(lat), Math.toDegrees(lon)); // in radian 204 194 } 205 195 206 196 /** 207 197 * Translate latitude/longitude in WGS84, (ellipsoid GRS80) to Lambert 208 198 * geographic, (ellipsoid Clark) 199 * @throws IOException 209 200 */ 210 private LatLon GRS802Clark(LatLon wgs) { 211 double lat = Math.toRadians(wgs.lat()); // degree to radian 212 double lon = Math.toRadians(wgs.lon()); 213 // WGS84 geographic => WGS84 cartesian 214 double N = Ellipsoid.GRS80.a / (Math.sqrt(1.0 - Ellipsoid.GRS80.e2 * Math.sin(lat) * Math.sin(lat))); 215 double X = (N/* +height */) * Math.cos(lat) * Math.cos(lon); 216 double Y = (N/* +height */) * Math.cos(lat) * Math.sin(lon); 217 double Z = (N * (1.0 - Ellipsoid.GRS80.e2)/* + height */) * Math.sin(lat); 218 // WGS84 => Lambert ellipsoide similarity 219 X += 168.0; 220 Y += 60.0; 221 Z += -320.0; 222 // Lambert cartesian => Lambert geographic 223 return Geographic(X, Y, Z, Ellipsoid.clarke); 201 private LatLon WGS84_to_NTF(LatLon wgs) { 202 NTV2GridShift gs = new NTV2GridShift(wgs); 203 if (ntf_rgf93Grid != null) { 204 ntf_rgf93Grid.gridShiftReverse(gs); 205 return new LatLon(wgs.lat()+gs.getLatShiftDegrees(), wgs.lon()+gs.getLonShiftPositiveEastDegrees()); 206 } 207 return new LatLon(0,0); 224 208 } 225 209 226 private LatLon Clark2GRS80(LatLon lambert) { 227 double lat = lambert.lat(); // in radian 228 double lon = lambert.lon(); 229 // Lambert geographic => Lambert cartesian 230 double N = Ellipsoid.clarke.a / (Math.sqrt(1.0 - Ellipsoid.clarke.e2 * Math.sin(lat) * Math.sin(lat))); 231 double X = (N/* +height */) * Math.cos(lat) * Math.cos(lon); 232 double Y = (N/* +height */) * Math.cos(lat) * Math.sin(lon); 233 double Z = (N * (1.0 - Ellipsoid.clarke.e2)/* + height */) * Math.sin(lat); 234 // Lambert => WGS84 ellipsoide similarity 235 X += -168.0; 236 Y += -60.0; 237 Z += 320.0; 238 // WGS84 cartesian => WGS84 geographic 239 return Geographic(X, Y, Z, Ellipsoid.GRS80); 210 private LatLon NTF_to_WGS84(LatLon ntf) { 211 NTV2GridShift gs = new NTV2GridShift(ntf); 212 if (ntf_rgf93Grid != null) { 213 ntf_rgf93Grid.gridShiftForward(gs); 214 return new LatLon(ntf.lat()+gs.getLatShiftDegrees(), ntf.lon()+gs.getLonShiftPositiveEastDegrees()); 215 } 216 return new LatLon(0,0); 240 217 } 241 218 219 public Bounds getWorldBoundsLatLon() 220 { 221 Bounds b= new Bounds( 222 new LatLon(zoneLimitsDegree[layoutZone][1] - cMaxOverlappingZonesDegree, -4.9074074074074059), 223 new LatLon(zoneLimitsDegree[layoutZone][0] + cMaxOverlappingZonesDegree, 10.2)); 224 return b; 225 } 226 242 227 /** 243 * initializes from cartesian coordinates 244 * 245 * @param X 246 * 1st coordinate in meters 247 * @param Y 248 * 2nd coordinate in meters 249 * @param Z 250 * 3rd coordinate in meters 251 * @param ell 252 * reference ellipsoid 228 * Returns the default zoom scale in pixel per degree ({@see #NavigatableComponent#scale})) 253 229 */ 254 private LatLon Geographic(double X, double Y, double Z, Ellipsoid ell) { 255 double norm = Math.sqrt(X * X + Y * Y); 256 double lg = 2.0 * Math.atan(Y / (X + norm)); 257 double lt = Math.atan(Z / (norm * (1.0 - (ell.a * ell.e2 / Math.sqrt(X * X + Y * Y + Z * Z))))); 258 double delta = 1.0; 259 while (delta > epsilon) { 260 double s2 = Math.sin(lt); 261 s2 *= s2; 262 double l = Math.atan((Z / norm) 263 / (1.0 - (ell.a * ell.e2 * Math.cos(lt) / (norm * Math.sqrt(1.0 - ell.e2 * s2))))); 264 delta = Math.abs(l - lt); 265 lt = l; 266 } 267 double s2 = Math.sin(lt); 268 s2 *= s2; 269 // h = norm / Math.cos(lt) - ell.a / Math.sqrt(1.0 - ell.e2 * s2); 270 return new LatLon(lt, lg); 230 public double getDefaultZoomInPPD() { 231 // this will set the map scaler to about 1000 m (in default scale, 1 pixel will be 10 meters) 232 return 10.0; 271 233 } 272 234 273 private boolean farawayFromLambertZoneFrance(double lat, double lon) { 274 if (lat < (zoneLimits[3] - cMaxOverlappingZones) || (lat > (cMaxLatZone1 + cMaxOverlappingZones)) 275 || (lon < (cMinLonZones - cMaxOverlappingZones)) || (lon > (cMaxLonZones + cMaxOverlappingZones))) 276 return true; 277 return false; 235 public int getLayoutZone() { 236 return layoutZone; 278 237 } 279 238 280 public Bounds getWorldBoundsLatLon() 281 { 282 // These are not the Lambert Zone boundaries but we keep these values until coordinates outside the 283 // projection boundaries are handled correctly. 284 return new Bounds( 285 new LatLon(-85.05112877980659, -180.0), 286 new LatLon(85.05112877980659, 180.0)); 287 /*return new Bounds( 288 new LatLon(45.0, -4.9074074074074059), 289 new LatLon(57.0, 10.2));*/ 239 public static String[] lambert4zones = { "1 (51.30 to 48.15 degrees)", 240 "2 (48.15 to 45.45 degrees)", 241 "3 (45.45 to 42.76 degrees)", 242 "4 (Corsica)" }; 243 244 public void setupPreferencePanel(JPanel p) { 245 JComboBox prefcb = new JComboBox(lambert4zones); 246 247 prefcb.setSelectedIndex(layoutZone); 248 p.setLayout(new GridBagLayout()); 249 p.add(new JLabel(tr("Lambert CC Zone")), GBC.std().insets(5,5,0,5)); 250 p.add(GBC.glue(1, 0), GBC.std().fill(GBC.HORIZONTAL)); 251 /* Note: we use component position 2 below to find this again */ 252 p.add(prefcb, GBC.eop().fill(GBC.HORIZONTAL)); 253 p.add(GBC.glue(1, 1), GBC.eol().fill(GBC.BOTH)); 290 254 } 291 255 292 public double getDefaultZoomInPPD() { 293 // TODO FIXME 294 return 0; 256 public Collection<String> getPreferences(JPanel p) { 257 Object prefcb = p.getComponent(2); 258 if(!(prefcb instanceof JComboBox)) 259 return null; 260 layoutZone = ((JComboBox)prefcb).getSelectedIndex(); 261 System.out.println("Current Lambert 4 zone:" + (layoutZone+1)); 262 return Collections.singleton(Integer.toString(layoutZone+1)); 295 263 } 264 265 public void setPreferences(Collection<String> args) { 266 layoutZone = DEFAULT_ZONE; 267 if (args != null) { 268 try { 269 for(String s : args) 270 { 271 layoutZone = Integer.parseInt(s)-1; 272 if(layoutZone < 0 || layoutZone > 3) { 273 layoutZone = DEFAULT_ZONE; 274 } 275 break; 276 } 277 } catch(NumberFormatException e) {} 278 } 279 System.out.println("Current Lambert 4 zone:" + (layoutZone+1)); 280 } 281 282 public Collection<String> getPreferencesFromCode(String code) { 283 if (code.startsWith("EPSG:2756") && code.length() == 9) { 284 try { 285 String zonestring = code.substring(9); 286 int zoneval = Integer.parseInt(zonestring); 287 if(zoneval >= 1 && zoneval <= 4) 288 return Collections.singleton(zonestring); 289 } catch(NumberFormatException e) {} 290 } 291 return null; 292 } 293 296 294 } -
LambertCC9Zones.java
3 3 4 4 import static org.openstreetmap.josm.tools.I18n.tr; 5 5 6 import javax.swing.JOptionPane; 6 import java.awt.GridBagLayout; 7 import java.util.Collection; 8 import java.util.Collections; 7 9 8 import org.openstreetmap.josm.Main; 10 import javax.swing.JComboBox; 11 import javax.swing.JLabel; 12 import javax.swing.JPanel; 13 9 14 import org.openstreetmap.josm.data.Bounds; 10 15 import org.openstreetmap.josm.data.coor.EastNorth; 11 16 import org.openstreetmap.josm.data.coor.LatLon; 12 17 import org.openstreetmap.josm.data.projection.Projection; 13 18 import org.openstreetmap.josm.data.projection.Ellipsoid; 19 import org.openstreetmap.josm.tools.GBC; 20 import org.openstreetmap.josm.tools.ImageProvider; 14 21 15 22 /** 16 23 * This class implements the Lambert Conic Conform 9 Zones projection as specified by the IGN … … 18 25 * @author Pieren 19 26 * 20 27 */ 21 public class LambertCC9Zones implements Projection {28 public class LambertCC9Zones implements Projection, ProjectionSubPrefs { 22 29 23 30 /** 24 31 * Lambert 9 zones projection exponents … … 57 64 /** 58 65 * France is divided in 9 Lambert projection zones, CC42 to CC50. 59 66 */ 60 public static final double cMaxLatZones = Math.toRadians(51.1);67 public static final double cMaxLatZonesRadian = Math.toRadians(51.1); 61 68 62 public static final double cMinLatZones = Math.toRadians(41.0); 69 public static final double cMinLatZonesDegree = 41.0; 70 public static final double cMinLatZonesRadian = Math.toRadians(cMinLatZonesDegree); 63 71 64 public static final double cMinLonZones = Math.toRadians(-5.0);72 public static final double cMinLonZonesRadian = Math.toRadians(-5.0); 65 73 66 public static final double cMaxLonZones = Math.toRadians(10.2);74 public static final double cMaxLonZonesRadian = Math.toRadians(10.2); 67 75 68 76 public static final double lambda0 = Math.toRadians(3); 69 77 public static final double e = Ellipsoid.GRS80.e; // but in doc=0.08181919112 70 78 public static final double e2 =Ellipsoid.GRS80.e2; 71 79 public static final double a = Ellipsoid.GRS80.a; 72 /**73 * Because josm cannot work correctly if two zones are displayed, we allow some overlapping74 */75 public static final double cMaxOverlappingZones = Math.toRadians(1.5);76 80 77 public static int layoutZone = -1;81 public static final double cMaxOverlappingZones = 1.5; 78 82 83 public static final int DEFAULT_ZONE = 0; 84 85 private static int layoutZone = DEFAULT_ZONE; 86 79 87 private double L(double phi, double e) { 80 88 double sinphi = Math.sin(phi); 81 89 return (0.5*Math.log((1+sinphi)/(1-sinphi))) - e/2*Math.log((1+e*sinphi)/(1-e*sinphi)); … … 88 96 public EastNorth latlon2eastNorth(LatLon p) { 89 97 double lt = Math.toRadians(p.lat()); 90 98 double lg = Math.toRadians(p.lon()); 91 // check if longitude and latitude are inside the French Lambert zones and seek a zone number 92 // if it is not already defined in layoutZone 93 int possibleZone = 0; 94 boolean outOfLambertZones = false; 95 if (lt >= cMinLatZones && lt <= cMaxLatZones && lg >= cMinLonZones && lg <= cMaxLonZones) { 96 /* with Lambert CC9 zones, each latitude is present in two zones. If the layout 97 zone is not already set, we choose arbitrary the first possible zone */ 98 possibleZone = (int)p.lat()-42; 99 if (possibleZone > 8) { 100 possibleZone = 8; 101 } 102 if (possibleZone < 0) { 103 possibleZone = 0; 104 } 105 } else { 106 outOfLambertZones = true; // possible when MAX_LAT is used 107 } 108 if (!outOfLambertZones) { 109 if (layoutZone == -1) { 110 if (layoutZone != possibleZone) { 111 System.out.println("change Lambert zone from "+layoutZone+" to "+possibleZone); 112 } 113 layoutZone = possibleZone; 114 } else if (Math.abs(layoutZone - possibleZone) > 1) { 115 if (farawayFromLambertZoneFrance(lt, lg)) { 116 JOptionPane.showMessageDialog(Main.parent, 117 tr("IMPORTANT : data positioned far away from\n" 118 + "the current Lambert zone limits.\n" 119 + "Do not upload any data after this message.\n" 120 + "Undo your last action, save your work\n" 121 + "and start a new layer on the new zone."), 122 tr("Warning"), 123 JOptionPane.WARNING_MESSAGE); 124 layoutZone = -1; 125 } else { 126 System.out.println("temporarily extend Lambert zone " + layoutZone + " projection at lat,lon:" 127 + lt + "," + lg); 128 } 129 } 130 } 131 if (layoutZone == -1) 132 return ConicProjection(lt, lg, possibleZone); 133 return ConicProjection(lt, lg, layoutZone); 99 if (lt >= cMinLatZonesRadian && lt <= cMaxLatZonesRadian && lg >= cMinLonZonesRadian && lg <= cMaxLonZonesRadian) 100 return ConicProjection(lt, lg, layoutZone); 101 return ConicProjection(lt, lg, 0); 134 102 } 135 103 136 104 /** … … 149 117 } 150 118 151 119 public LatLon eastNorth2latlon(EastNorth p) { 152 layoutZone = north2ZoneNumber(p.north());153 120 return Geographic(p, layoutZone); 154 121 } 155 122 … … 173 140 else return nz; 174 141 } 175 142 176 public static boolean isInL9CCZones(LatLon p) {177 double lt = Math.toRadians(p.lat());178 double lg = Math.toRadians(p.lon());179 if (lg >= cMinLonZones && lg <= cMaxLonZones && lt >= cMinLatZones && lt <= cMaxLatZones)180 return true;181 return false;182 }183 184 143 public String toCode() { 185 if (layoutZone == -1) 186 return "EPSG:"+(3942); 187 return "EPSG:"+(3942+layoutZone); //CC42 is EPSG:3842 (up to EPSG:3950 for CC50) 144 return "EPSG:"+(3942+layoutZone); //CC42 is EPSG:3942 (up to EPSG:3950 for CC50) 188 145 } 189 146 190 147 public String getCacheDirectoryName() { 191 148 return "lambert"; 192 149 } 193 150 194 private boolean farawayFromLambertZoneFrance(double lat, double lon) { 195 if (lat < (cMinLatZones - cMaxOverlappingZones) || (lat > (cMaxLatZones + cMaxOverlappingZones)) 196 || (lon < (cMinLonZones - cMaxOverlappingZones)) || (lon > (cMaxLonZones + cMaxOverlappingZones))) 197 return true; 198 return false; 199 } 200 151 /** 152 * Returns the default zoom scale in pixel per degree ({@see #NavigatableComponent#scale})) 153 */ 201 154 public double getDefaultZoomInPPD() { 202 // TODO Auto-generated method stub203 return 0;155 // this will set the map scaler to about 1000 m (in default scale, 1 pixel will be 10 meters) 156 return 10.0; 204 157 } 205 158 206 159 public Bounds getWorldBoundsLatLon() 207 160 { 208 // These are not the Lambert Zone boundaries but we keep these values until coordinates outside the 209 // projection boundaries are handled correctly. 161 double medLatZone = cMinLatZonesDegree + (layoutZone+1); 210 162 return new Bounds( 211 new LatLon(-85.05112877980659, -180.0), 212 new LatLon(85.05112877980659, 180.0)); 213 /*return new Bounds( 214 new LatLon(45.0, -4.9074074074074059), 215 new LatLon(57.0, 10.2));*/ 163 new LatLon(medLatZone - 1.0 - cMaxOverlappingZones, -4.9), 164 new LatLon(medLatZone + 1.0 + cMaxOverlappingZones, 10.2)); 216 165 } 217 166 167 public int getLayoutZone() { 168 return layoutZone; 169 } 170 171 private static String[] lambert9zones = { "1 (41 to 43 degrees)", "2 (42 to 44 degrees)", 172 "3 (43 to 45 degrees)", "4 (44 to 46 degrees)", "5 (45 to 47 degrees)", 173 "6 (46 to 48 degrees)", "7 (47 to 49 degrees)", "8 (48 to 50 degrees)", 174 "9 (49 to 51 degrees)" }; 175 176 public void setupPreferencePanel(JPanel p) { 177 JComboBox prefcb = new JComboBox(lambert9zones); 178 179 prefcb.setSelectedIndex(layoutZone); 180 p.setLayout(new GridBagLayout()); 181 p.add(new JLabel(tr("Lambert CC Zone")), GBC.std().insets(5,5,0,5)); 182 p.add(GBC.glue(1, 0), GBC.std().fill(GBC.HORIZONTAL)); 183 /* Note: we use component position 2 below to find this again */ 184 p.add(prefcb, GBC.eop().fill(GBC.HORIZONTAL)); 185 p.add(new JLabel(ImageProvider.get("data/projection", "LambertCC9Zones.png")), GBC.eol().fill(GBC.HORIZONTAL)); 186 p.add(GBC.glue(1, 1), GBC.eol().fill(GBC.BOTH)); 187 } 188 189 public Collection<String> getPreferences(JPanel p) { 190 Object prefcb = p.getComponent(2); 191 if(!(prefcb instanceof JComboBox)) 192 return null; 193 layoutZone = ((JComboBox)prefcb).getSelectedIndex(); 194 System.out.println("Current Lambert CC 9 zone:" + (layoutZone+1)); 195 if (layoutZone == 0) { 196 layoutZone = layoutZone +1 -1; 197 } 198 return Collections.singleton(Integer.toString(layoutZone+1)); 199 } 200 201 public void setPreferences(Collection<String> args) 202 { 203 layoutZone = DEFAULT_ZONE; 204 if (args != null) { 205 try { 206 for(String s : args) 207 { 208 layoutZone = Integer.parseInt(s)-1; 209 if(layoutZone < 0 || layoutZone > 8) { 210 layoutZone = DEFAULT_ZONE; 211 } 212 break; 213 } 214 } catch(NumberFormatException e) {} 215 } 216 System.out.println("Current Lambert CC 9 zone:" + (layoutZone+1)); 217 if (layoutZone == 0) { 218 layoutZone = layoutZone +1 -1; 219 } 220 } 221 222 public Collection<String> getPreferencesFromCode(String code) 223 { 224 //zone 1=CC42=EPSG:3942 up to zone 9=CC50=EPSG:3950 225 if (code.startsWith("EPSG:39") && code.length() == 9) { 226 try { 227 String zonestring = code.substring(5,4); 228 int zoneval = Integer.parseInt(zonestring)-3942; 229 if(zoneval >= 0 && zoneval <= 8) 230 return Collections.singleton(zonestring); 231 } catch(NumberFormatException e) {} 232 } 233 return null; 234 } 235 218 236 } 219 237 -
Projection.java
27 27 new Lambert(), // Still needs proper default zoom 28 28 new SwissGrid(), 29 29 new UTM(), 30 new UTM_20N_Guadeloupe_Ste_Anne(), 31 new UTM_20N_Guadeloupe_Fort_Marigot(), 32 new UTM_20N_Martinique_Fort_Desaix(), 30 new UTM_20N_France_DOM(), 33 31 new GaussLaborde_Reunion(), 34 32 new LambertCC9Zones() // Still needs proper default zoom 35 33 }; -
UTM_20N_France_DOM.java
2 2 package org.openstreetmap.josm.data.projection; 3 3 4 4 /** 5 * This class is not a direct implementation of Projection. It collects all methods used 6 * for the projection of the French departements in the Caribbean Sea UTM zone 20N 7 * but using each time different local geodesic settings for the 7 parameters transformation algorithm. 5 * This class implements all projections for French departements in the Caribbean Sea using 6 * UTM zone 20N transvers Mercator and specific geodesic settings (7 parameters transformation algorithm). 8 7 */ 8 import static org.openstreetmap.josm.tools.I18n.tr; 9 10 import java.awt.GridBagLayout; 11 import java.util.Collection; 12 import java.util.Collections; 13 14 import javax.swing.JComboBox; 15 import javax.swing.JLabel; 16 import javax.swing.JPanel; 17 18 import org.openstreetmap.josm.data.Bounds; 9 19 import org.openstreetmap.josm.data.coor.EastNorth; 10 20 import org.openstreetmap.josm.data.coor.LatLon; 21 import org.openstreetmap.josm.tools.GBC; 11 22 12 public class UTM_20N_France_DOM {23 public class UTM_20N_France_DOM implements Projection, ProjectionSubPrefs { 13 24 25 private static String FortMarigotName = tr("Guadeloupe Fort-Marigot 1949"); 26 private static String SainteAnneName = tr("Guadeloupe Ste-Anne 1948"); 27 private static String MartiniqueName = tr("Martinique Fort Desaix 1952"); 28 public static String[] utmGeodesicsNames = { FortMarigotName, SainteAnneName, MartiniqueName}; 29 30 private Bounds FortMarigotBounds = new Bounds( new LatLon(17.6,-63.25), new LatLon(18.5,-62.5)); 31 private Bounds SainteAnneBounds = new Bounds( new LatLon(15.8,-61.9), new LatLon(16.6,-60.9)); 32 private Bounds MartiniqueBounds = new Bounds( new LatLon(14.25,-61.25), new LatLon(15.025,-60.725)); 33 private Bounds[] utmBounds = { FortMarigotBounds, SainteAnneBounds, MartiniqueBounds}; 34 35 private String FortMarigotEPSG = "EPSG::2969"; 36 private String SainteAnneEPSG = "EPSG::2970"; 37 private String MartiniqueEPSG = "EPSG::2973"; 38 private String[] utmEPSGs = { FortMarigotEPSG, SainteAnneEPSG, MartiniqueEPSG}; 39 14 40 /** 15 41 * false east in meters (constant) 16 42 */ … … 27 53 /** 28 54 * UTM zone (from 1 to 60) 29 55 */ 30 int zone= 20;56 private static int ZONE = 20; 31 57 /** 32 58 * whether north or south hemisphere 33 59 */ 34 60 private boolean isNorth = true; 61 62 public static final int DEFAULT_GEODESIC = 0; 63 64 private static int currentGeodesic = DEFAULT_GEODESIC; 65 35 66 /** 36 67 * 7 parameters transformation 37 68 */ 38 double tx = 0.0;39 double ty = 0.0;40 double tz = 0.0;41 double rx = 0;42 double ry = 0;43 double rz = 0;44 double scaleDiff = 0;69 private static double tx = 0.0; 70 private static double ty = 0.0; 71 private static double tz = 0.0; 72 private static double rx = 0; 73 private static double ry = 0; 74 private static double rz = 0; 75 private static double scaleDiff = 0; 45 76 /** 46 77 * precision in iterative schema 47 78 */ … … 49 80 public final static double DEG_TO_RAD = Math.PI / 180; 50 81 public final static double RAD_TO_DEG = 180 / Math.PI; 51 82 52 public UTM_20N_France_DOM(double[] translation, double[] rotation, double scaleDiff) { 53 this.tx = translation[0]; 54 this.ty = translation[1]; 55 this.tz = translation[2]; 56 this.rx = rotation[0]/206264.806247096355; // seconds to radian 57 this.ry = rotation[1]/206264.806247096355; 58 this.rz = rotation[2]/206264.806247096355; 59 this.scaleDiff = scaleDiff; 83 private void refresh7ParametersTranslation() { 84 System.out.println("Current UTM geodesic system: " + utmGeodesicsNames[currentGeodesic]); 85 if (currentGeodesic == 0) { // UTM_20N_Guadeloupe_Fort_Marigot 86 set7ParametersTranslation(new double[]{136.596, 248.148, -429.789}, 87 new double[]{0, 0, 0}, 88 0); 89 } else if (currentGeodesic == 1) { // UTM_20N_Guadeloupe_Ste_Anne 90 set7ParametersTranslation(new double[]{-472.29, -5.63, -304.12}, 91 new double[]{0.4362, -0.8374, 0.2563}, 92 1.8984E-6); 93 } else { // UTM_20N_Martinique_Fort_Desaix 94 set7ParametersTranslation(new double[]{126.926, 547.939, 130.409}, 95 new double[]{-2.78670, 5.16124, -0.85844}, 96 13.82265E-6); 97 } 60 98 } 99 100 private void set7ParametersTranslation(double[] translation, double[] rotation, double scalediff) { 101 tx = translation[0]; 102 ty = translation[1]; 103 tz = translation[2]; 104 rx = rotation[0]/206264.806247096355; // seconds to radian 105 ry = rotation[1]/206264.806247096355; 106 rz = rotation[2]/206264.806247096355; 107 scaleDiff = scalediff; 108 } 109 61 110 public EastNorth latlon2eastNorth(LatLon p) { 62 111 // translate ellipsoid GRS80 (WGS83) => reference ellipsoid geographic 63 112 LatLon geo = GRS802Hayford(p); … … 127 176 Ys = (coord.lat() >= 0.0) ? 0.0 : 10000000.0; 128 177 double r6d = Math.PI / 30.0; 129 178 //zone = (int) Math.floor((coord.lon() + Math.PI) / r6d) + 1; 130 lg0 = r6d * ( zone- 0.5) - Math.PI;179 lg0 = r6d * (ZONE - 0.5) - Math.PI; 131 180 double e2 = e * e; 132 181 double e4 = e2 * e2; 133 182 double e6 = e4 * e2; … … 168 217 } 169 218 170 219 public LatLon eastNorth2latlon(EastNorth p) { 171 MTProjection(p.east(), p.north(), zone, isNorth);220 MTProjection(p.east(), p.north(), ZONE, isNorth); 172 221 LatLon geo = Geographic(p, Ellipsoid.hayford.a, Ellipsoid.hayford.e, 0.0 /* z */); 173 222 174 223 // reference ellipsoid geographic => reference ellipsoid cartesian 175 //Hayford2GRS80(ellipsoid, geo);176 224 double N = Ellipsoid.hayford.a / (Math.sqrt(1.0 - Ellipsoid.hayford.e2 * Math.sin(geo.lat()) * Math.sin(geo.lat()))); 177 225 double X = (N /*+ h*/) * Math.cos(geo.lat()) * Math.cos(geo.lon()); 178 226 double Y = (N /*+ h*/) * Math.cos(geo.lat()) * Math.sin(geo.lon()); … … 309 357 return new double[]{Xb, Yb, Zb}; 310 358 } 311 359 360 public String getCacheDirectoryName() { 361 return this.toString(); 362 } 363 364 /** 365 * Returns the default zoom scale in pixel per degree ({@see #NavigatableComponent#scale})) 366 */ 367 public double getDefaultZoomInPPD() { 368 // this will set the map scaler to about 1000 m (in default scale, 1 pixel will be 10 meters) 369 return 10.0; 370 } 371 372 public Bounds getWorldBoundsLatLon() { 373 return utmBounds[currentGeodesic]; 374 } 375 376 public String toCode() { 377 return utmEPSGs[currentGeodesic]; 378 } 379 380 @Override public String toString() { 381 return (tr("UTM 20N (France)")); 382 } 383 384 public int getCurrentGeodesic() { 385 return currentGeodesic; 386 } 387 388 public void setupPreferencePanel(JPanel p) { 389 JComboBox prefcb = new JComboBox(utmGeodesicsNames); 390 391 prefcb.setSelectedIndex(currentGeodesic); 392 p.setLayout(new GridBagLayout()); 393 p.add(new JLabel(tr("UTM20 North Geodesic system")), GBC.std().insets(5,5,0,5)); 394 p.add(GBC.glue(1, 0), GBC.std().fill(GBC.HORIZONTAL)); 395 p.add(prefcb, GBC.eop().fill(GBC.HORIZONTAL)); 396 p.add(GBC.glue(1, 1), GBC.eol().fill(GBC.BOTH)); 397 } 398 399 public Collection<String> getPreferences(JPanel p) { 400 Object prefcb = p.getComponent(2); 401 if(!(prefcb instanceof JComboBox)) 402 return null; 403 currentGeodesic = ((JComboBox)prefcb).getSelectedIndex(); 404 refresh7ParametersTranslation(); 405 return Collections.singleton(Integer.toString(currentGeodesic+1)); 406 } 407 408 public Collection<String> getPreferencesFromCode(String code) { 409 for (int i=0; i < utmEPSGs.length; i++ ) 410 if (utmEPSGs[i].endsWith(code)) 411 return Collections.singleton(Integer.toString(i)); 412 return null; 413 } 414 415 public void setPreferences(Collection<String> args) { 416 currentGeodesic = DEFAULT_GEODESIC; 417 if (args != null) { 418 try { 419 for(String s : args) 420 { 421 currentGeodesic = Integer.parseInt(s)-1; 422 if(currentGeodesic < 0 || currentGeodesic > 2) { 423 currentGeodesic = DEFAULT_GEODESIC; 424 } 425 break; 426 } 427 } catch(NumberFormatException e) {} 428 } 429 refresh7ParametersTranslation(); 430 } 431 312 432 }
