source: josm/trunk/src/org/openstreetmap/josm/data/projection/LambertCC9Zones.java@ 3779

Last change on this file since 3779 was 3779, checked in by Upliner, 13 years ago

Identify projections in offset bookmarks by EPSG codes, bugfixes in getPreferencesFromCode() functions as they're critical now.

  • Property svn:eol-style set to native
File size: 8.8 KB
Line 
1//License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data.projection;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.GridBagLayout;
7import java.awt.event.ActionListener;
8import java.util.Collection;
9import java.util.Collections;
10
11import javax.swing.JComboBox;
12import javax.swing.JLabel;
13import javax.swing.JPanel;
14
15import org.openstreetmap.josm.data.Bounds;
16import org.openstreetmap.josm.data.coor.EastNorth;
17import org.openstreetmap.josm.data.coor.LatLon;
18import org.openstreetmap.josm.tools.GBC;
19import org.openstreetmap.josm.tools.ImageProvider;
20
21/**
22 * This class implements the Lambert Conic Conform 9 Zones projection as specified by the IGN
23 * in this document http://professionnels.ign.fr/DISPLAY/000/526/700/5267002/transformation.pdf
24 * @author Pieren
25 *
26 */
27public class LambertCC9Zones implements Projection, ProjectionSubPrefs {
28
29 /**
30 * Lambert 9 zones projection exponents
31 */
32 public static final double n[] = { 0.6691500006885269, 0.682018118346418, 0.6946784863203991, 0.7071272481559119,
33 0.7193606118567315, 0.7313748510399917, 0.7431663060711892, 0.7547313851789208, 0.7660665655489937};
34
35 /**
36 * Lambert 9 zones projection constants
37 */
38 public static final double c[] = { 1.215363305807804E7, 1.2050261119223533E7, 1.195716926884592E7, 1.18737533925172E7,
39 1.1799460698022118E7, 1.17337838820243E7, 1.16762559948139E7, 1.1626445901183508E7, 1.1583954251630554E7};
40
41 /**
42 * Lambert 9 zones false east
43 */
44 public static final double Xs = 1700000;
45
46 /**
47 * Lambert 9 zones false north
48 */
49 public static final double Ys[] = { 8293467.503439436, 9049604.665107645, 9814691.693461388, 1.0588107871787189E7,
50 1.1369285637569271E7, 1.2157704903382052E7, 1.2952888086405803E7, 1.3754395745267643E7, 1.4561822739114787E7};
51
52 /**
53 * Lambert I, II, III, and IV longitudinal offset to Greenwich meridian
54 */
55 public static final double lg0 = 0.04079234433198; // 2deg20'14.025"
56
57 /**
58 * precision in iterative schema
59 */
60
61 public static final double epsilon = 1e-12;
62
63 /**
64 * France is divided in 9 Lambert projection zones, CC42 to CC50.
65 */
66 public static final double cMaxLatZonesRadian = Math.toRadians(51.1);
67
68 public static final double cMinLatZonesDegree = 41.0;
69 public static final double cMinLatZonesRadian = Math.toRadians(cMinLatZonesDegree);
70
71 public static final double cMinLonZonesRadian = Math.toRadians(-5.0);
72
73 public static final double cMaxLonZonesRadian = Math.toRadians(10.2);
74
75 public static final double lambda0 = Math.toRadians(3);
76 public static final double e = Ellipsoid.GRS80.e; // but in doc=0.08181919112
77 public static final double e2 =Ellipsoid.GRS80.e2;
78 public static final double a = Ellipsoid.GRS80.a;
79
80 public static final double cMaxOverlappingZones = 1.5;
81
82 public static final int DEFAULT_ZONE = 0;
83
84 private static int layoutZone = DEFAULT_ZONE;
85
86 private double L(double phi, double e) {
87 double sinphi = Math.sin(phi);
88 return (0.5*Math.log((1+sinphi)/(1-sinphi))) - e/2*Math.log((1+e*sinphi)/(1-e*sinphi));
89 }
90
91 /**
92 * @param p WGS84 lat/lon (ellipsoid GRS80) (in degree)
93 * @return eastnorth projection in Lambert Zone (ellipsoid Clark)
94 */
95 public EastNorth latlon2eastNorth(LatLon p) {
96 double lt = Math.toRadians(p.lat());
97 double lg = Math.toRadians(p.lon());
98 if (lt >= cMinLatZonesRadian && lt <= cMaxLatZonesRadian && lg >= cMinLonZonesRadian && lg <= cMaxLonZonesRadian)
99 return ConicProjection(lt, lg, layoutZone);
100 return ConicProjection(lt, lg, 0);
101 }
102
103 /**
104 *
105 * @param lat latitude in grad
106 * @param lon longitude in grad
107 * @param nz Lambert CC zone number (from 1 to 9) - 1 !
108 * @return EastNorth projected coordinates in meter
109 */
110 private EastNorth ConicProjection(double lat, double lon, int nz) {
111 double R = c[nz]*Math.exp(-n[nz]*L(lat,e));
112 double gamma = n[nz]*(lon-lambda0);
113 double X = Xs + R*Math.sin(gamma);
114 double Y = Ys[nz] + -R*Math.cos(gamma);
115 return new EastNorth(X, Y);
116 }
117
118 public LatLon eastNorth2latlon(EastNorth p) {
119 return Geographic(p, layoutZone);
120 }
121
122 private LatLon Geographic(EastNorth ea, int nz) {
123 double R = Math.sqrt(Math.pow(ea.getX()-Xs,2)+Math.pow(ea.getY()-Ys[nz], 2));
124 double gamma = Math.atan((ea.getX()-Xs)/(Ys[nz]-ea.getY()));
125 double lon = lambda0+gamma/n[nz];
126 double latIso = (-1/n[nz])*Math.log(Math.abs(R/c[nz]));
127 double lat = Ellipsoid.GRS80.latitude(latIso, e, epsilon);
128 return new LatLon(Math.toDegrees(lat), Math.toDegrees(lon));
129 }
130
131 @Override public String toString() {
132 return tr("Lambert CC9 Zone (France)");
133 }
134
135 public static int north2ZoneNumber(double north) {
136 int nz = (int)(north /1000000) - 1;
137 if (nz < 0) return 0;
138 else if (nz > 8) return 8;
139 else return nz;
140 }
141
142 public String toCode() {
143 return "EPSG:"+(3942+layoutZone); //CC42 is EPSG:3942 (up to EPSG:3950 for CC50)
144 }
145
146 @Override
147 public int hashCode() {
148 return getClass().getName().hashCode()+layoutZone; // our only real variable
149 }
150
151 public String getCacheDirectoryName() {
152 return "lambert";
153 }
154
155 /**
156 * Returns the default zoom scale in pixel per degree ({@see #NavigatableComponent#scale}))
157 */
158 public double getDefaultZoomInPPD() {
159 // this will set the map scaler to about 1000 m (in default scale, 1 pixel will be 10 meters)
160 return 10.0;
161 }
162
163 public Bounds getWorldBoundsLatLon()
164 {
165 double medLatZone = cMinLatZonesDegree + (layoutZone+1);
166 return new Bounds(
167 new LatLon(Math.max(medLatZone - 1.0 - cMaxOverlappingZones, cMinLatZonesDegree), -4.9),
168 new LatLon(Math.min(medLatZone + 1.0 + cMaxOverlappingZones, Math.toDegrees(cMaxLatZonesRadian)), 10.2));
169 }
170
171 public int getLayoutZone() {
172 return layoutZone;
173 }
174
175 private static String[] lambert9zones = {
176 tr("{0} ({1} to {2} degrees)", 1,41,43),
177 tr("{0} ({1} to {2} degrees)", 2,42,44),
178 tr("{0} ({1} to {2} degrees)", 3,43,45),
179 tr("{0} ({1} to {2} degrees)", 4,44,46),
180 tr("{0} ({1} to {2} degrees)", 5,45,47),
181 tr("{0} ({1} to {2} degrees)", 6,46,48),
182 tr("{0} ({1} to {2} degrees)", 7,47,49),
183 tr("{0} ({1} to {2} degrees)", 8,48,50),
184 tr("{0} ({1} to {2} degrees)", 9,49,51)
185 };
186
187 @Override
188 public void setupPreferencePanel(JPanel p, ActionListener listener) {
189 JComboBox prefcb = new JComboBox(lambert9zones);
190
191 prefcb.setSelectedIndex(layoutZone);
192 p.setLayout(new GridBagLayout());
193 p.add(new JLabel(tr("Lambert CC Zone")), GBC.std().insets(5,5,0,5));
194 p.add(GBC.glue(1, 0), GBC.std().fill(GBC.HORIZONTAL));
195 /* Note: we use component position 2 below to find this again */
196 p.add(prefcb, GBC.eop().fill(GBC.HORIZONTAL));
197 p.add(new JLabel(ImageProvider.get("data/projection", "LambertCC9Zones.png")), GBC.eol().fill(GBC.HORIZONTAL));
198 p.add(GBC.glue(1, 1), GBC.eol().fill(GBC.BOTH));
199
200 if (listener != null) {
201 prefcb.addActionListener(listener);
202 }
203 }
204
205 public Collection<String> getPreferences(JPanel p) {
206 Object prefcb = p.getComponent(2);
207 if(!(prefcb instanceof JComboBox))
208 return null;
209 layoutZone = ((JComboBox)prefcb).getSelectedIndex();
210 return Collections.singleton(Integer.toString(layoutZone+1));
211 }
212
213 public void setPreferences(Collection<String> args)
214 {
215 layoutZone = DEFAULT_ZONE;
216 if (args != null) {
217 try {
218 for(String s : args)
219 {
220 layoutZone = Integer.parseInt(s)-1;
221 if(layoutZone < 0 || layoutZone > 8) {
222 layoutZone = DEFAULT_ZONE;
223 }
224 break;
225 }
226 } catch(NumberFormatException e) {}
227 }
228 }
229
230 @Override
231 public String[] allCodes() {
232 String[] zones = new String[9];
233 for (int zone = 0; zone < 9; zone++) {
234 zones[zone] = "EPSG:" + (3942 + zone);
235 }
236 return zones;
237 }
238
239 public Collection<String> getPreferencesFromCode(String code)
240 {
241 //zone 1=CC42=EPSG:3942 up to zone 9=CC50=EPSG:3950
242 if (code.startsWith("EPSG:39") && code.length() == 9) {
243 try {
244 String zonestring = code.substring(5,9);
245 int zoneval = Integer.parseInt(zonestring)-3942;
246 if(zoneval >= 0 && zoneval <= 8)
247 return Collections.singleton(String.valueOf(zoneval+1));
248 } catch(NumberFormatException e) {}
249 }
250 return null;
251 }
252}
Note: See TracBrowser for help on using the repository browser.