Changeset 2507 in josm


Ignore:
Timestamp:
2009-11-22T22:39:10+01:00 (14 years ago)
Author:
stoecker
Message:

apply #2989 - patch by pieren - improve lambert projection

Location:
trunk
Files:
8 added
3 deleted
8 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/build.xml

    r2453 r2507  
    100100                        <zipfileset dir="presets" prefix="presets" />
    101101                        <zipfileset dir="images" prefix="images" />
     102                        <zipfileset dir="data" prefix="data" />
    102103                        <zipfileset src="lib/josm-translation.jar" />
    103104
  • trunk/src/org/openstreetmap/josm/data/projection/Ellipsoid.java

    r2304 r2507  
    165165    }
    166166}
    167 
    168 
    169 
  • trunk/src/org/openstreetmap/josm/data/projection/GaussLaborde_Reunion.java

    r2114 r2507  
    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}
  • trunk/src/org/openstreetmap/josm/data/projection/Lambert.java

    r2304 r2507  
    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;
     11
     12import javax.swing.JComboBox;
     13import javax.swing.JLabel;
     14import javax.swing.JPanel;
    1015
    1116import org.openstreetmap.josm.Main;
     
    1318import org.openstreetmap.josm.data.coor.EastNorth;
    1419import org.openstreetmap.josm.data.coor.LatLon;
    15 
    16 public class Lambert implements Projection {
     20import org.openstreetmap.josm.tools.GBC;
     21
     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
     
    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);
    52 
    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
    57 
    58     public static final double cMinLonZones = Math.toRadians(-4.9074074074074059 * 0.9);
    59 
    60     public static final double cMaxLonZones = Math.toRadians(10.2 * 0.9);
    61 
    62     /**
    63      *  Because josm cannot work correctly if two zones are displayed, we allow some overlapping
    64      */
    65     public static final double cMaxOverlappingZones = Math.toRadians(1.5 * 0.9);
    66 
    67     public static int layoutZone = -1;
    68 
    69     private static int currentZone = 0;
     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)
     67
     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    };
     74
     75    public static final double cMinLonZonesRadian = Math.toRadians(-4.9074074074074059 * 0.9);
     76
     77    public static final double cMaxLonZonesRadian = Math.toRadians(10.2 * 0.9);
     78
     79    /**
     80     *  Allow some extension beyond the theoretical limits
     81     */
     82    public static final double cMaxOverlappingZonesDegree = 1.5;
     83
     84    public static final int DEFAULT_ZONE = 0;
     85
     86    private static int layoutZone = DEFAULT_ZONE;
     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("/data/"+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    }
    70107
    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
     
    145135
    146136    public String toCode() {
    147         return "EPSG:"+(27561+currentZone);
     137        return "EPSG:"+(27561+layoutZone);
    148138    }
    149139
     
    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) {
     
    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
     
    207197     * Translate latitude/longitude in WGS84, (ellipsoid GRS80) to Lambert
    208198     * geographic, (ellipsoid Clark)
    209      */
    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);
    224     }
    225 
    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);
    240     }
    241 
    242     /**
    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
    253      */
    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);
    271     }
    272 
    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;
     199     * @throws IOException
     200     */
     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);
     208    }
     209
     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);
    278217    }
    279218
    280219    public Bounds getWorldBoundsLatLon()
    281220    {
    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));*/
    290     }
    291 
     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
     227    /**
     228     * Returns the default zoom scale in pixel per degree ({@see #NavigatableComponent#scale}))
     229     */
    292230    public double getDefaultZoomInPPD() {
    293         // TODO FIXME
    294         return 0;
    295     }
     231        // this will set the map scaler to about 1000 m (in default scale, 1 pixel will be 10 meters)
     232        return 10.0;
     233    }
     234
     235    public int getLayoutZone() {
     236        return layoutZone;
     237    }
     238
     239    public static String[] lambert4zones = {
     240        tr("{0} ({1} to {2} degrees)", 1,"51.30","48.15"),
     241        tr("{0} ({1} to {2} degrees)", 1,"48.15","45.45"),
     242        tr("{0} ({1} to {2} degrees)", 1,"45.45","42.76"),
     243        tr("{0} (Corsica)", 4)
     244    };
     245
     246    public void setupPreferencePanel(JPanel p) {
     247        JComboBox prefcb = new JComboBox(lambert4zones);
     248
     249        prefcb.setSelectedIndex(layoutZone);
     250        p.setLayout(new GridBagLayout());
     251        p.add(new JLabel(tr("Lambert CC Zone")), GBC.std().insets(5,5,0,5));
     252        p.add(GBC.glue(1, 0), GBC.std().fill(GBC.HORIZONTAL));
     253        /* Note: we use component position 2 below to find this again */
     254        p.add(prefcb, GBC.eop().fill(GBC.HORIZONTAL));
     255        p.add(GBC.glue(1, 1), GBC.eol().fill(GBC.BOTH));
     256    }
     257
     258    public Collection<String> getPreferences(JPanel p) {
     259        Object prefcb = p.getComponent(2);
     260        if(!(prefcb instanceof JComboBox))
     261            return null;
     262        layoutZone = ((JComboBox)prefcb).getSelectedIndex();
     263        return Collections.singleton(Integer.toString(layoutZone+1));
     264    }
     265
     266    public void setPreferences(Collection<String> args) {
     267        layoutZone = DEFAULT_ZONE;
     268        if (args != null) {
     269            try {
     270                for(String s : args)
     271                {
     272                    layoutZone = Integer.parseInt(s)-1;
     273                    if(layoutZone < 0 || layoutZone > 3) {
     274                        layoutZone = DEFAULT_ZONE;
     275                    }
     276                    break;
     277                }
     278            } catch(NumberFormatException e) {}
     279        }
     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}
  • trunk/src/org/openstreetmap/josm/data/projection/LambertCC9Zones.java

    r2304 r2507  
    44import static org.openstreetmap.josm.tools.I18n.tr;
    55
    6 import javax.swing.JOptionPane;
    7 
    8 import org.openstreetmap.josm.Main;
     6import java.awt.GridBagLayout;
     7import java.util.Collection;
     8import java.util.Collections;
     9
     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;
     
    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/**
     
    1926 *
    2027 */
    21 public class LambertCC9Zones implements Projection {
     28public class LambertCC9Zones implements Projection, ProjectionSubPrefs {
    2229
    2330    /**
     
    5865     * France is divided in 9 Lambert projection zones, CC42 to CC50.
    5966     */
    60     public static final double cMaxLatZones = Math.toRadians(51.1);
    61 
    62     public static final double cMinLatZones = Math.toRadians(41.0);
    63 
    64     public static final double cMinLonZones = Math.toRadians(-5.0);
    65 
    66     public static final double cMaxLonZones = Math.toRadians(10.2);
     67    public static final double cMaxLatZonesRadian = Math.toRadians(51.1);
     68
     69    public static final double cMinLatZonesDegree = 41.0;
     70    public static final double cMinLatZonesRadian = Math.toRadians(cMinLatZonesDegree);
     71
     72    public static final double cMinLonZonesRadian = Math.toRadians(-5.0);
     73
     74    public static final double cMaxLonZonesRadian = Math.toRadians(10.2);
    6775
    6876    public static final double lambda0 = Math.toRadians(3);
     
    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);
    76 
    77     public static int layoutZone = -1;
     80
     81    public static final double cMaxOverlappingZones = 1.5;
     82
     83    public static final int DEFAULT_ZONE = 0;
     84
     85    private static int layoutZone = DEFAULT_ZONE;
    7886
    7987    private double L(double phi, double e) {
     
    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);
    134     }
    135 
    136     /**
    137      *
     99        if (lt >= cMinLatZonesRadian && lt <= cMaxLatZonesRadian && lg >= cMinLonZonesRadian && lg <= cMaxLonZonesRadian)
     100            return ConicProjection(lt, lg, layoutZone);
     101        return ConicProjection(lt, lg, 0);
     102    }
     103
     104    /**
     105     *
    138106     * @param lat latitude in grad
    139107     * @param lon longitude in grad
     
    150118
    151119    public LatLon eastNorth2latlon(EastNorth p) {
    152         layoutZone  = north2ZoneNumber(p.north());
    153120        return Geographic(p, layoutZone);
    154121    }
     
    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
     
    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));*/
    216     }
    217 
     163                new LatLon(medLatZone - 1.0 - cMaxOverlappingZones, -4.9),
     164                new LatLon(medLatZone + 1.0 + cMaxOverlappingZones, 10.2));
     165    }
     166
     167    public int getLayoutZone() {
     168        return layoutZone;
     169    }
     170
     171    private static String[] lambert9zones = {
     172        tr("{0} ({1} to {2} degrees)", 1,41,43),
     173        tr("{0} ({1} to {2} degrees)", 2,42,44),
     174        tr("{0} ({1} to {2} degrees)", 3,43,45),
     175        tr("{0} ({1} to {2} degrees)", 4,44,46),
     176        tr("{0} ({1} to {2} degrees)", 5,45,47),
     177        tr("{0} ({1} to {2} degrees)", 6,46,48),
     178        tr("{0} ({1} to {2} degrees)", 7,47,49),
     179        tr("{0} ({1} to {2} degrees)", 8,48,50),
     180        tr("{0} ({1} to {2} degrees)", 9,49,51)
     181    };
     182
     183    public void setupPreferencePanel(JPanel p) {
     184        JComboBox prefcb = new JComboBox(lambert9zones);
     185
     186        prefcb.setSelectedIndex(layoutZone);
     187        p.setLayout(new GridBagLayout());
     188        p.add(new JLabel(tr("Lambert CC Zone")), GBC.std().insets(5,5,0,5));
     189        p.add(GBC.glue(1, 0), GBC.std().fill(GBC.HORIZONTAL));
     190        /* Note: we use component position 2 below to find this again */
     191        p.add(prefcb, GBC.eop().fill(GBC.HORIZONTAL));
     192        p.add(new JLabel(ImageProvider.get("data/projection", "LambertCC9Zones.png")), GBC.eol().fill(GBC.HORIZONTAL));
     193        p.add(GBC.glue(1, 1), GBC.eol().fill(GBC.BOTH));
     194    }
     195
     196    public Collection<String> getPreferences(JPanel p) {
     197        Object prefcb = p.getComponent(2);
     198        if(!(prefcb instanceof JComboBox))
     199            return null;
     200        layoutZone = ((JComboBox)prefcb).getSelectedIndex();
     201        if (layoutZone == 0) {
     202            layoutZone = layoutZone +1 -1;
     203        }
     204        return Collections.singleton(Integer.toString(layoutZone+1));
     205    }
     206
     207    public void setPreferences(Collection<String> args)
     208    {
     209        layoutZone = DEFAULT_ZONE;
     210        if (args != null) {
     211            try {
     212                for(String s : args)
     213                {
     214                    layoutZone = Integer.parseInt(s)-1;
     215                    if(layoutZone < 0 || layoutZone > 8) {
     216                        layoutZone = DEFAULT_ZONE;
     217                    }
     218                    break;
     219                }
     220            } catch(NumberFormatException e) {}
     221        }
     222        if (layoutZone == 0) {
     223            layoutZone = layoutZone +1 -1;
     224        }
     225    }
     226
     227    public Collection<String> getPreferencesFromCode(String code)
     228    {
     229        //zone 1=CC42=EPSG:3942 up to zone 9=CC50=EPSG:3950
     230        if (code.startsWith("EPSG:39") && code.length() == 9) {
     231            try {
     232                String zonestring = code.substring(5,4);
     233                int zoneval = Integer.parseInt(zonestring)-3942;
     234                if(zoneval >= 0 && zoneval <= 8)
     235                    return Collections.singleton(zonestring);
     236            } catch(NumberFormatException e) {}
     237        }
     238        return null;
     239    }
    218240}
    219 
  • trunk/src/org/openstreetmap/josm/data/projection/Projection.java

    r2304 r2507  
    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
  • trunk/src/org/openstreetmap/josm/data/projection/ProjectionSubPrefs.java

    r2499 r2507  
    1010     * Generates the GUI for the given preference and packs them in a JPanel
    1111     * so they may be displayed if the projection is selected.
    12      *
    13      * Implementation hints:
    14      * <ul>
    15      *      <li>Do not return <code>null</code> as it is assumed that if this
    16      *      interface is implemented the projection actually has prefs to
    17      *      display/save.</li>
    18      *      <li>Cache the JPanel in a local variable so that changes are
    19      *      persistent even if the user chooses another projection in between.
    20      *      Destroy the panel on destroyCachedPanel() so that the pre-selected
    21      *      settings may update the preferences are updated from the outside</li>
    22      *      </li>
    23      * @return
    2412     */
    2513    public void setupPreferencePanel(JPanel p);
  • trunk/src/org/openstreetmap/josm/data/projection/UTM_20N_France_DOM.java

    r1929 r2507  
    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;
    11 
    12 public class UTM_20N_France_DOM {
     21import org.openstreetmap.josm.tools.GBC;
     22
     23public class UTM_20N_France_DOM implements Projection, ProjectionSubPrefs {
     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};
    1339
    1440    /**
     
    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
     
    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;
    60     }
     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        }
     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
    61110    public EastNorth latlon2eastNorth(LatLon p) {
    62111        // translate ellipsoid GRS80 (WGS83) => reference ellipsoid geographic
     
    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;
     
    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());
     
    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}
Note: See TracChangeset for help on using the changeset viewer.