| 1 | // License: GPL. For details, see LICENSE file. |
|---|
| 2 | package org.openstreetmap.josm.data.projection; |
|---|
| 3 | |
|---|
| 4 | import static org.openstreetmap.josm.tools.I18n.tr; |
|---|
| 5 | |
|---|
| 6 | import java.awt.GridBagLayout; |
|---|
| 7 | import java.awt.event.ActionListener; |
|---|
| 8 | import java.util.Collection; |
|---|
| 9 | import java.util.Collections; |
|---|
| 10 | |
|---|
| 11 | import javax.swing.JComboBox; |
|---|
| 12 | import javax.swing.JLabel; |
|---|
| 13 | import javax.swing.JPanel; |
|---|
| 14 | |
|---|
| 15 | import org.openstreetmap.josm.data.Bounds; |
|---|
| 16 | import org.openstreetmap.josm.data.coor.LatLon; |
|---|
| 17 | import org.openstreetmap.josm.data.projection.datum.NTV2Datum; |
|---|
| 18 | import org.openstreetmap.josm.data.projection.datum.NTV2GridShiftFileWrapper; |
|---|
| 19 | import org.openstreetmap.josm.data.projection.proj.LambertConformalConic; |
|---|
| 20 | import org.openstreetmap.josm.data.projection.proj.ProjParameters; |
|---|
| 21 | import org.openstreetmap.josm.tools.GBC; |
|---|
| 22 | import org.openstreetmap.josm.tools.ImageProvider; |
|---|
| 23 | |
|---|
| 24 | /** |
|---|
| 25 | * 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 | * |
|---|
| 29 | * Source: http://professionnels.ign.fr/DISPLAY/000/526/700/5267002/transformation.pdf |
|---|
| 30 | * @author Pieren |
|---|
| 31 | */ |
|---|
| 32 | public class Lambert extends AbstractProjection { |
|---|
| 33 | |
|---|
| 34 | /** |
|---|
| 35 | * Lambert I, II, III, and IV latitude origin |
|---|
| 36 | */ |
|---|
| 37 | private static final double lat_0s[] = { 49.5, 46.8, 44.1, 42.165 }; |
|---|
| 38 | |
|---|
| 39 | /** |
|---|
| 40 | * Lambert I, II, III, and IV latitude of first standard parallel |
|---|
| 41 | */ |
|---|
| 42 | private static final double lat_1s[] = { |
|---|
| 43 | convertDegreeMinuteSecond(48, 35, 54.682), |
|---|
| 44 | convertDegreeMinuteSecond(45, 53, 56.108), |
|---|
| 45 | convertDegreeMinuteSecond(43, 11, 57.449), |
|---|
| 46 | convertDegreeMinuteSecond(41, 33, 37.396)}; |
|---|
| 47 | |
|---|
| 48 | /** |
|---|
| 49 | * Lambert I, II, III, and IV latitude of second standard parallel |
|---|
| 50 | */ |
|---|
| 51 | private static final double lat_2s[] = { |
|---|
| 52 | convertDegreeMinuteSecond(50, 23, 45.282), |
|---|
| 53 | convertDegreeMinuteSecond(47, 41, 45.652), |
|---|
| 54 | convertDegreeMinuteSecond(44, 59, 45.938), |
|---|
| 55 | convertDegreeMinuteSecond(42, 46, 3.588)}; |
|---|
| 56 | |
|---|
| 57 | /** |
|---|
| 58 | * Lambert I, II, III, and IV false east |
|---|
| 59 | */ |
|---|
| 60 | private static final double x_0s[] = { 600000.0, 600000.0, 600000.0, 234.358 }; |
|---|
| 61 | |
|---|
| 62 | /** |
|---|
| 63 | * Lambert I, II, III, and IV false north |
|---|
| 64 | */ |
|---|
| 65 | private static final double y_0s[] = { 200000.0, 200000.0, 200000.0, 185861.369 }; |
|---|
| 66 | |
|---|
| 67 | /** |
|---|
| 68 | * France is divided in 4 Lambert projection zones (1,2,3 + 4th for Corsica) |
|---|
| 69 | */ |
|---|
| 70 | public static final double cMaxLatZone1Radian = Math.toRadians(57 * 0.9); |
|---|
| 71 | public static final double cMinLatZone1Radian = Math.toRadians(46.1 * 0.9);// lowest latitude of Zone 4 (South Corsica) |
|---|
| 72 | |
|---|
| 73 | public static final double[][] zoneLimitsDegree = { |
|---|
| 74 | {Math.toDegrees(cMaxLatZone1Radian), (53.5 * 0.9)}, // Zone 1 (reference values in grad *0.9) |
|---|
| 75 | {(53.5 * 0.9), (50.5 * 0.9)}, // Zone 2 |
|---|
| 76 | {(50.5 * 0.9), (47.0 * 0.9)}, // Zone 3 |
|---|
| 77 | {(47.51963 * 0.9), Math.toDegrees(cMinLatZone1Radian)} // Zone 4 |
|---|
| 78 | }; |
|---|
| 79 | |
|---|
| 80 | public static final double cMinLonZonesRadian = Math.toRadians(-4.9074074074074059 * 0.9); |
|---|
| 81 | |
|---|
| 82 | public static final double cMaxLonZonesRadian = Math.toRadians(10.2 * 0.9); |
|---|
| 83 | |
|---|
| 84 | /** |
|---|
| 85 | * Allow some extension beyond the theoretical limits |
|---|
| 86 | */ |
|---|
| 87 | public static final double cMaxOverlappingZonesDegree = 1.5; |
|---|
| 88 | |
|---|
| 89 | public static final int DEFAULT_ZONE = 0; |
|---|
| 90 | |
|---|
| 91 | private int layoutZone; |
|---|
| 92 | |
|---|
| 93 | public Lambert() { |
|---|
| 94 | this(DEFAULT_ZONE); |
|---|
| 95 | } |
|---|
| 96 | |
|---|
| 97 | public Lambert(final int layoutZone) { |
|---|
| 98 | if (layoutZone < 0 || layoutZone >= 4) |
|---|
| 99 | throw new IllegalArgumentException(); |
|---|
| 100 | this.layoutZone = layoutZone; |
|---|
| 101 | ellps = Ellipsoid.clarkeIGN; |
|---|
| 102 | datum = new NTV2Datum("ntf_rgf93Grid", null, ellps, NTV2GridShiftFileWrapper.ntf_rgf93); |
|---|
| 103 | x_0 = x_0s[layoutZone]; |
|---|
| 104 | y_0 = y_0s[layoutZone]; |
|---|
| 105 | lon_0 = 2.0 + 20.0 / 60 + 14.025 / 3600; // 0 grade Paris |
|---|
| 106 | if (proj == null) { |
|---|
| 107 | proj = new LambertConformalConic(); |
|---|
| 108 | } |
|---|
| 109 | proj = new LambertConformalConic(); |
|---|
| 110 | try { |
|---|
| 111 | proj.initialize(new ProjParameters() {{ |
|---|
| 112 | ellps = Lambert.this.ellps; |
|---|
| 113 | lat_0 = lat_0s[layoutZone]; |
|---|
| 114 | lat_1 = lat_1s[layoutZone]; |
|---|
| 115 | lat_2 = lat_2s[layoutZone]; |
|---|
| 116 | }}); |
|---|
| 117 | } catch (ProjectionConfigurationException e) { |
|---|
| 118 | throw new RuntimeException(e); |
|---|
| 119 | } |
|---|
| 120 | } |
|---|
| 121 | |
|---|
| 122 | @Override |
|---|
| 123 | public String toString() { |
|---|
| 124 | return tr("Lambert 4 Zones (France)"); |
|---|
| 125 | } |
|---|
| 126 | |
|---|
| 127 | @Override |
|---|
| 128 | public Integer getEpsgCode() { |
|---|
| 129 | return 27561+layoutZone; |
|---|
| 130 | } |
|---|
| 131 | |
|---|
| 132 | @Override |
|---|
| 133 | public int hashCode() { |
|---|
| 134 | return getClass().getName().hashCode()+layoutZone; // our only real variable |
|---|
| 135 | } |
|---|
| 136 | |
|---|
| 137 | @Override |
|---|
| 138 | public String getCacheDirectoryName() { |
|---|
| 139 | return "lambert"; |
|---|
| 140 | } |
|---|
| 141 | |
|---|
| 142 | @Override |
|---|
| 143 | public Bounds getWorldBoundsLatLon() |
|---|
| 144 | { |
|---|
| 145 | Bounds b= new Bounds( |
|---|
| 146 | new LatLon(Math.max(zoneLimitsDegree[layoutZone][1] - cMaxOverlappingZonesDegree, Math.toDegrees(cMinLatZone1Radian)), Math.toDegrees(cMinLonZonesRadian)), |
|---|
| 147 | new LatLon(Math.min(zoneLimitsDegree[layoutZone][0] + cMaxOverlappingZonesDegree, Math.toDegrees(cMaxLatZone1Radian)), Math.toDegrees(cMaxLonZonesRadian)), |
|---|
| 148 | false); |
|---|
| 149 | return b; |
|---|
| 150 | } |
|---|
| 151 | |
|---|
| 152 | public int getLayoutZone() { |
|---|
| 153 | return layoutZone; |
|---|
| 154 | } |
|---|
| 155 | |
|---|
| 156 | } |
|---|