Ticket #3989: projection.patch

File projection.patch, 36.3 KB (added by pieren, 16 years ago)
  • GaussLaborde_Reunion.java

     
    216216    }
    217217
    218218    public double getDefaultZoomInPPD() {
    219         // this will set the map scaler to about 1000 m
    220         return 10.02;
     219        // this will set the map scaler to about 1000 m (in default scale, 1 pixel will be 10 meters)
     220        return 10.0;
    221221    }
    222222}
  • 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.
    52package org.openstreetmap.josm.data.projection;
    63
    74import static org.openstreetmap.josm.tools.I18n.tr;
    85
    9 import javax.swing.JOptionPane;
     6import java.awt.GridBagLayout;
     7import java.io.IOException;
     8import java.io.InputStream;
     9import java.util.Collection;
     10import java.util.Collections;
    1011
     12import javax.swing.JComboBox;
     13import javax.swing.JLabel;
     14import javax.swing.JPanel;
     15
    1116import org.openstreetmap.josm.Main;
    1217import org.openstreetmap.josm.data.Bounds;
    1318import org.openstreetmap.josm.data.coor.EastNorth;
    1419import org.openstreetmap.josm.data.coor.LatLon;
     20import org.openstreetmap.josm.tools.GBC;
    1521
    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 */
     30public class Lambert implements Projection, ProjectionSubPrefs {
    1731    /**
    1832     * Lambert I, II, III, and IV projection exponents
    1933     */
     
    4862    /**
    4963     * France is divided in 4 Lambert projection zones (1,2,3 + 4th for Corsica)
    5064     */
    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)
    5267
    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    };
    5774
    58     public static final double cMinLonZones = Math.toRadians(-4.9074074074074059 * 0.9);
     75    public static final double cMinLonZonesRadian = Math.toRadians(-4.9074074074074059 * 0.9);
    5976
    60     public static final double cMaxLonZones = Math.toRadians(10.2 * 0.9);
     77    public static final double cMaxLonZonesRadian = Math.toRadians(10.2 * 0.9);
    6178
    6279    /**
    63      *  Because josm cannot work correctly if two zones are displayed, we allow some overlapping
     80     *  Allow some extension beyond the theoretical limits
    6481     */
    65     public static final double cMaxOverlappingZones = Math.toRadians(1.5 * 0.9);
     82    public static final double cMaxOverlappingZonesDegree = 1.5;
    6683
    67     public static int layoutZone = -1;
     84    public static final int DEFAULT_ZONE = 0;
    6885
    69     private static int currentZone = 0;
     86    private static int layoutZone = DEFAULT_ZONE;
    7087
     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
    71108    /**
    72109     * @param p  WGS84 lat/lon (ellipsoid GRS80) (in degree)
    73110     * @return eastnorth projection in Lambert Zone (ellipsoid Clark)
     111     * @throws IOException
    74112     */
    75113    public EastNorth latlon2eastNorth(LatLon p) {
    76114        // translate ellipsoid GRS80 (WGS83) => Clark
    77         LatLon geo = GRS802Clark(p);
    78         double lt = geo.lat(); // in radian
    79         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());
    80118
    81119        // 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]);
    127123    }
    128124
    129125    public LatLon eastNorth2latlon(EastNorth p) {
    130126        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);
    140130    }
    141131
    142132    @Override public String toString() {
     
    144134    }
    145135
    146136    public String toCode() {
    147         return "EPSG:"+(27561+currentZone);
     137        return "EPSG:"+(27561+layoutZone);
    148138    }
    149139
    150140    public String getCacheDirectoryName() {
     
    181171     * @param Ys        false north (coordinate system origin) in meters
    182172     * @param c         projection constant
    183173     * @param n         projection exponent
    184      * @return LatLon in radian
     174     * @return LatLon in degree
    185175     */
    186176    private LatLon Geographic(EastNorth eastNorth, double Xs, double Ys, double c, double n) {
    187177        double dx = eastNorth.east() - Xs;
     
    200190            delta = Math.abs(nlt - lat);
    201191            lat = nlt;
    202192        }
    203         return new LatLon(lat, lon); // in radian
     193        return new LatLon(Math.toDegrees(lat), Math.toDegrees(lon)); // in radian
    204194    }
    205195
    206196    /**
    207197     * Translate latitude/longitude in WGS84, (ellipsoid GRS80) to Lambert
    208198     * geographic, (ellipsoid Clark)
     199     * @throws IOException
    209200     */
    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);
    224208    }
    225209
    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);
    240217    }
    241218
     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
    242227    /**
    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}))
    253229     */
    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;
    271233    }
    272234
    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;
    278237    }
    279238
    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));
    290254    }
    291255
    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));
    295263    }
     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
    296294}
  • LambertCC9Zones.java

     
    33
    44import static org.openstreetmap.josm.tools.I18n.tr;
    55
    6 import javax.swing.JOptionPane;
     6import java.awt.GridBagLayout;
     7import java.util.Collection;
     8import java.util.Collections;
    79
    8 import org.openstreetmap.josm.Main;
     10import javax.swing.JComboBox;
     11import javax.swing.JLabel;
     12import javax.swing.JPanel;
     13
    914import org.openstreetmap.josm.data.Bounds;
    1015import org.openstreetmap.josm.data.coor.EastNorth;
    1116import org.openstreetmap.josm.data.coor.LatLon;
    1217import org.openstreetmap.josm.data.projection.Projection;
    1318import org.openstreetmap.josm.data.projection.Ellipsoid;
     19import org.openstreetmap.josm.tools.GBC;
     20import org.openstreetmap.josm.tools.ImageProvider;
    1421
    1522/**
    1623 * This class implements the Lambert Conic Conform 9 Zones projection as specified by the IGN
     
    1825 * @author Pieren
    1926 *
    2027 */
    21 public class LambertCC9Zones implements Projection {
     28public class LambertCC9Zones implements Projection, ProjectionSubPrefs {
    2229
    2330    /**
    2431     * Lambert 9 zones projection exponents
     
    5764    /**
    5865     * France is divided in 9 Lambert projection zones, CC42 to CC50.
    5966     */
    60     public static final double cMaxLatZones = Math.toRadians(51.1);
     67    public static final double cMaxLatZonesRadian = Math.toRadians(51.1);
    6168
    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);
    6371
    64     public static final double cMinLonZones = Math.toRadians(-5.0);
     72    public static final double cMinLonZonesRadian = Math.toRadians(-5.0);
    6573
    66     public static final double cMaxLonZones = Math.toRadians(10.2);
     74    public static final double cMaxLonZonesRadian = Math.toRadians(10.2);
    6775
    6876    public static final double lambda0 = Math.toRadians(3);
    6977    public static final double e = Ellipsoid.GRS80.e; // but in doc=0.08181919112
    7078    public static final double e2 =Ellipsoid.GRS80.e2;
    7179    public static final double a = Ellipsoid.GRS80.a;
    72     /**
    73      *  Because josm cannot work correctly if two zones are displayed, we allow some overlapping
    74      */
    75     public static final double cMaxOverlappingZones = Math.toRadians(1.5);
    7680
    77     public static int layoutZone = -1;
     81    public static final double cMaxOverlappingZones = 1.5;
    7882
     83    public static final int DEFAULT_ZONE = 0;
     84
     85    private static int layoutZone = DEFAULT_ZONE;
     86
    7987    private double L(double phi, double e) {
    8088        double sinphi = Math.sin(phi);
    8189        return (0.5*Math.log((1+sinphi)/(1-sinphi))) - e/2*Math.log((1+e*sinphi)/(1-e*sinphi));
     
    8896    public EastNorth latlon2eastNorth(LatLon p) {
    8997        double lt = Math.toRadians(p.lat());
    9098        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);
    134102    }
    135103
    136104    /**
     
    149117    }
    150118
    151119    public LatLon eastNorth2latlon(EastNorth p) {
    152         layoutZone  = north2ZoneNumber(p.north());
    153120        return Geographic(p, layoutZone);
    154121    }
    155122
     
    173140        else return nz;
    174141    }
    175142
    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 
    184143    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)
    188145    }
    189146
    190147    public String getCacheDirectoryName() {
    191148        return "lambert";
    192149    }
    193150
    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     */
    201154    public double getDefaultZoomInPPD() {
    202         // TODO Auto-generated method stub
    203         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;
    204157    }
    205158
    206159    public Bounds getWorldBoundsLatLon()
    207160    {
    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);
    210162        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));
    216165    }
    217166
     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
    218236}
    219237
  • Projection.java

     
    2727        new Lambert(),    // Still needs proper default zoom
    2828        new SwissGrid(),
    2929        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(),
    3331        new GaussLaborde_Reunion(),
    3432        new LambertCC9Zones()    // Still needs proper default zoom
    3533    };
  • UTM_20N_France_DOM.java

     
    22package org.openstreetmap.josm.data.projection;
    33
    44/**
    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).
    87 */
     8import static org.openstreetmap.josm.tools.I18n.tr;
     9
     10import java.awt.GridBagLayout;
     11import java.util.Collection;
     12import java.util.Collections;
     13
     14import javax.swing.JComboBox;
     15import javax.swing.JLabel;
     16import javax.swing.JPanel;
     17
     18import org.openstreetmap.josm.data.Bounds;
    919import org.openstreetmap.josm.data.coor.EastNorth;
    1020import org.openstreetmap.josm.data.coor.LatLon;
     21import org.openstreetmap.josm.tools.GBC;
    1122
    12 public class UTM_20N_France_DOM {
     23public class UTM_20N_France_DOM implements Projection, ProjectionSubPrefs {
    1324
     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
    1440    /**
    1541     * false east in meters (constant)
    1642     */
     
    2753    /**
    2854     * UTM zone (from 1 to 60)
    2955     */
    30     int zone = 20;
     56    private static int ZONE = 20;
    3157    /**
    3258     * whether north or south hemisphere
    3359     */
    3460    private boolean isNorth = true;
     61
     62    public static final int DEFAULT_GEODESIC = 0;
     63
     64    private static int currentGeodesic = DEFAULT_GEODESIC;
     65
    3566    /**
    3667     * 7 parameters transformation
    3768     */
    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;
    4576    /**
    4677     * precision in iterative schema
    4778     */
     
    4980    public final static double DEG_TO_RAD = Math.PI / 180;
    5081    public final static double RAD_TO_DEG = 180 / Math.PI;
    5182
    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        }
    6098    }
     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
    61110    public EastNorth latlon2eastNorth(LatLon p) {
    62111        // translate ellipsoid GRS80 (WGS83) => reference ellipsoid geographic
    63112        LatLon geo = GRS802Hayford(p);
     
    127176        Ys = (coord.lat() >= 0.0) ? 0.0 : 10000000.0;
    128177        double r6d = Math.PI / 30.0;
    129178        //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;
    131180        double e2 = e * e;
    132181        double e4 = e2 * e2;
    133182        double e6 = e4 * e2;
     
    168217    }
    169218
    170219    public LatLon eastNorth2latlon(EastNorth p) {
    171         MTProjection(p.east(), p.north(), zone, isNorth);
     220        MTProjection(p.east(), p.north(), ZONE, isNorth);
    172221        LatLon geo = Geographic(p, Ellipsoid.hayford.a, Ellipsoid.hayford.e, 0.0 /* z */);
    173222
    174223        // reference ellipsoid geographic => reference ellipsoid cartesian
    175         //Hayford2GRS80(ellipsoid, geo);
    176224        double N = Ellipsoid.hayford.a / (Math.sqrt(1.0 - Ellipsoid.hayford.e2 * Math.sin(geo.lat()) * Math.sin(geo.lat())));
    177225        double X = (N /*+ h*/) * Math.cos(geo.lat()) * Math.cos(geo.lon());
    178226        double Y = (N /*+ h*/) * Math.cos(geo.lat()) * Math.sin(geo.lon());
     
    309357        return new double[]{Xb, Yb, Zb};
    310358    }
    311359
     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
    312432}