Index: GaussLaborde_Reunion.java
===================================================================
--- GaussLaborde_Reunion.java	(revision 2500)
+++ GaussLaborde_Reunion.java	(working copy)
@@ -216,7 +216,7 @@
     }
 
     public double getDefaultZoomInPPD() {
-        // this will set the map scaler to about 1000 m
-        return 10.02;
+        // this will set the map scaler to about 1000 m (in default scale, 1 pixel will be 10 meters)
+        return 10.0;
     }
 }
Index: Lambert.java
===================================================================
--- Lambert.java	(revision 2500)
+++ Lambert.java	(working copy)
@@ -1,19 +1,33 @@
-//License: GPL. For details, see LICENSE file.
-//Thanks to Johan Montagnat and its geoconv java converter application
-//(http://www.i3s.unice.fr/~johan/gps/ , published under GPL license)
-//from which some code and constants have been reused here.
+// License: GPL. For details, see LICENSE file.
 package org.openstreetmap.josm.data.projection;
 
 import static org.openstreetmap.josm.tools.I18n.tr;
 
-import javax.swing.JOptionPane;
+import java.awt.GridBagLayout;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collection;
+import java.util.Collections;
 
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.Bounds;
 import org.openstreetmap.josm.data.coor.EastNorth;
 import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.tools.GBC;
 
-public class Lambert implements Projection {
+/**
+ * This class provides the two methods <code>latlon2eastNorth</code> and <code>eastNorth2latlon</code>
+ * converting the JOSM LatLon coordinates in WGS84 system (GPS) to and from East North values in
+ * the projection Lambert conic conform 4 zones using the French geodetic system NTF.
+ * This newer version uses the grid translation NTF<->RGF93 provided by IGN for a submillimetric accuracy.
+ * (RGF93 is the French geodetic system similar to WGS84 but not mathematically equal)
+ * @author Pieren
+ */
+public class Lambert implements Projection, ProjectionSubPrefs {
     /**
      * Lambert I, II, III, and IV projection exponents
      */
@@ -48,95 +62,71 @@
     /**
      * France is divided in 4 Lambert projection zones (1,2,3 + 4th for Corsica)
      */
-    public static final double cMaxLatZone1 = Math.toRadians(57 * 0.9);
+    public static final double cMaxLatZone1Radian = Math.toRadians(57 * 0.9);
+    public static final double cMinLatZone1Radian = Math.toRadians(46.1 * 0.9);// lowest latitude of Zone 4 (South Corsica)
 
-    public static final double zoneLimits[] = { Math.toRadians(53.5 * 0.9), // between Zone 1 and Zone 2 (in grad *0.9)
-        Math.toRadians(50.5 * 0.9), // between Zone 2 and Zone 3
-        Math.toRadians(47.51963 * 0.9), // between Zone 3 and Zone 4
-        Math.toRadians(46.17821 * 0.9) };// lowest latitude of Zone 4
+    public static final double zoneLimitsDegree[][] = {
+        {Math.toDegrees(cMaxLatZone1Radian), (53.5 * 0.9)}, // Zone 1  (reference values in grad *0.9)
+        {(53.5 * 0.9), (50.5 * 0.9)}, // Zone 2
+        {(50.5 * 0.9), (47.0 * 0.9)}, // Zone 3
+        {(47.51963 * 0.9), Math.toDegrees(cMinLatZone1Radian)} // Zone 4
+    };
 
-    public static final double cMinLonZones = Math.toRadians(-4.9074074074074059 * 0.9);
+    public static final double cMinLonZonesRadian = Math.toRadians(-4.9074074074074059 * 0.9);
 
-    public static final double cMaxLonZones = Math.toRadians(10.2 * 0.9);
+    public static final double cMaxLonZonesRadian = Math.toRadians(10.2 * 0.9);
 
     /**
-     *  Because josm cannot work correctly if two zones are displayed, we allow some overlapping
+     *  Allow some extension beyond the theoretical limits
      */
-    public static final double cMaxOverlappingZones = Math.toRadians(1.5 * 0.9);
+    public static final double cMaxOverlappingZonesDegree = 1.5;
 
-    public static int layoutZone = -1;
+    public static final int DEFAULT_ZONE = 0;
 
-    private static int currentZone = 0;
+    private static int layoutZone = DEFAULT_ZONE;
 
+    private static NTV2GridShiftFile ntf_rgf93Grid = null;
+
+    public static NTV2GridShiftFile getNtf_rgf93Grid() {
+        return ntf_rgf93Grid;
+    }
+
+    public Lambert() {
+        if (ntf_rgf93Grid == null) {
+            try {
+                String gridFileName = "ntf_r93_b.gsb";
+                InputStream is = Main.class.getResourceAsStream("/images/data/projection/"+gridFileName);
+                ntf_rgf93Grid = new NTV2GridShiftFile();
+                ntf_rgf93Grid.loadGridShiftFile(is, false);
+                System.out.println("NTF<->RGF93 grid loaded.");
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
     /**
      * @param p  WGS84 lat/lon (ellipsoid GRS80) (in degree)
      * @return eastnorth projection in Lambert Zone (ellipsoid Clark)
+     * @throws IOException
      */
     public EastNorth latlon2eastNorth(LatLon p) {
         // translate ellipsoid GRS80 (WGS83) => Clark
-        LatLon geo = GRS802Clark(p);
-        double lt = geo.lat(); // in radian
-        double lg = geo.lon();
+        LatLon geo = WGS84_to_NTF(p);
+        double lt = Math.toRadians(geo.lat()); // in radian
+        double lg = Math.toRadians(geo.lon());
 
         // check if longitude and latitude are inside the French Lambert zones
-        currentZone = 0;
-        boolean outOfLambertZones = false;
-        if (lt >= zoneLimits[3] && lt <= cMaxLatZone1 && lg >= cMinLonZones && lg <= cMaxLonZones) {
-            // zone I
-            if (lt > zoneLimits[0]) {
-                currentZone = 0;
-            } else if (lt > zoneLimits[1]) {
-                currentZone = 1;
-            } else if (lt > zoneLimits[2]) {
-                currentZone = 2;
-            } else if (lt > zoneLimits[3])
-                // Note: zone IV is dedicated to Corsica island and extends from 47.8 to
-                // 45.9 degrees of latitude. There is an overlap with zone III that can be
-                // solved only with longitude (covers Corsica if lon > 7.2 degree)
-                if (lg < Math.toRadians(8 * 0.9)) {
-                    currentZone = 2;
-                } else {
-                    currentZone = 3;
-                }
-        } else {
-            outOfLambertZones = true; // possible when MAX_LAT is used
-        }
-        if (!outOfLambertZones) {
-            if (layoutZone == -1) {
-                layoutZone = currentZone;
-            } else if (layoutZone != currentZone) {
-                if (farawayFromLambertZoneFrance(lt,lg)) {
-                    JOptionPane.showMessageDialog(Main.parent,
-                            tr("IMPORTANT : data positioned far away from\n"
-                                    + "the current Lambert zone limits.\n"
-                                    + "Do not upload any data after this message.\n"
-                                    + "Undo your last action, save your work\n"
-                                    + "and start a new layer on the new zone."),
-                                    tr("Warning"),
-                                    JOptionPane.WARNING_MESSAGE);
-                    layoutZone = -1;
-                } else {
-                    System.out.println("temporarily extend Lambert zone " + layoutZone + " projection at lat,lon:"
-                            + lt + "," + lg);
-                }
-            }
-        }
-        if (layoutZone == -1)
-            return ConicProjection(lt, lg, Xs[currentZone], Ys[currentZone], c[currentZone], n[currentZone]);
-        return ConicProjection(lt, lg, Xs[layoutZone], Ys[layoutZone], c[layoutZone], n[layoutZone]);
+        if (lt >= cMinLatZone1Radian && lt <= cMaxLatZone1Radian && lg >= cMinLonZonesRadian && lg <= cMaxLonZonesRadian)
+            return ConicProjection(lt, lg, Xs[layoutZone], Ys[layoutZone], c[layoutZone], n[layoutZone]);
+        return ConicProjection(lt, lg, Xs[0], Ys[0], c[0], n[0]);
     }
 
     public LatLon eastNorth2latlon(EastNorth p) {
         LatLon geo;
-        if (layoutZone == -1) {
-            // possible until the Lambert zone is determined by latlon2eastNorth() with a valid LatLon
-            geo = Geographic(p, Xs[currentZone], Ys[currentZone], c[currentZone], n[currentZone]);
-        } else {
-            geo = Geographic(p, Xs[layoutZone], Ys[layoutZone], c[layoutZone], n[layoutZone]);
-        }
-        // translate ellipsoid Clark => GRS80 (WGS83)
-        LatLon wgs = Clark2GRS80(geo);
-        return new LatLon(Math.toDegrees(wgs.lat()), Math.toDegrees(wgs.lon()));
+        geo = Geographic(p, Xs[layoutZone], Ys[layoutZone], c[layoutZone], n[layoutZone]);
+        // translate geodetic system from NTF (ellipsoid Clark) to RGF93/WGS84 (ellipsoid GRS80)
+        return NTF_to_WGS84(geo);
     }
 
     @Override public String toString() {
@@ -144,7 +134,7 @@
     }
 
     public String toCode() {
-        return "EPSG:"+(27561+currentZone);
+        return "EPSG:"+(27561+layoutZone);
     }
 
     public String getCacheDirectoryName() {
@@ -181,7 +171,7 @@
      * @param Ys        false north (coordinate system origin) in meters
      * @param c         projection constant
      * @param n         projection exponent
-     * @return LatLon in radian
+     * @return LatLon in degree
      */
     private LatLon Geographic(EastNorth eastNorth, double Xs, double Ys, double c, double n) {
         double dx = eastNorth.east() - Xs;
@@ -200,97 +190,105 @@
             delta = Math.abs(nlt - lat);
             lat = nlt;
         }
-        return new LatLon(lat, lon); // in radian
+        return new LatLon(Math.toDegrees(lat), Math.toDegrees(lon)); // in radian
     }
 
     /**
      * Translate latitude/longitude in WGS84, (ellipsoid GRS80) to Lambert
      * geographic, (ellipsoid Clark)
+     * @throws IOException
      */
-    private LatLon GRS802Clark(LatLon wgs) {
-        double lat = Math.toRadians(wgs.lat()); // degree to radian
-        double lon = Math.toRadians(wgs.lon());
-        // WGS84 geographic => WGS84 cartesian
-        double N = Ellipsoid.GRS80.a / (Math.sqrt(1.0 - Ellipsoid.GRS80.e2 * Math.sin(lat) * Math.sin(lat)));
-        double X = (N/* +height */) * Math.cos(lat) * Math.cos(lon);
-        double Y = (N/* +height */) * Math.cos(lat) * Math.sin(lon);
-        double Z = (N * (1.0 - Ellipsoid.GRS80.e2)/* + height */) * Math.sin(lat);
-        // WGS84 => Lambert ellipsoide similarity
-        X += 168.0;
-        Y += 60.0;
-        Z += -320.0;
-        // Lambert cartesian => Lambert geographic
-        return Geographic(X, Y, Z, Ellipsoid.clarke);
+    private LatLon WGS84_to_NTF(LatLon wgs) {
+        NTV2GridShift gs = new NTV2GridShift(wgs);
+        if (ntf_rgf93Grid != null) {
+            ntf_rgf93Grid.gridShiftReverse(gs);
+            return new LatLon(wgs.lat()+gs.getLatShiftDegrees(), wgs.lon()+gs.getLonShiftPositiveEastDegrees());
+        }
+        return new LatLon(0,0);
     }
 
-    private LatLon Clark2GRS80(LatLon lambert) {
-        double lat = lambert.lat(); // in radian
-        double lon = lambert.lon();
-        // Lambert geographic => Lambert cartesian
-        double N = Ellipsoid.clarke.a / (Math.sqrt(1.0 - Ellipsoid.clarke.e2 * Math.sin(lat) * Math.sin(lat)));
-        double X = (N/* +height */) * Math.cos(lat) * Math.cos(lon);
-        double Y = (N/* +height */) * Math.cos(lat) * Math.sin(lon);
-        double Z = (N * (1.0 - Ellipsoid.clarke.e2)/* + height */) * Math.sin(lat);
-        // Lambert => WGS84 ellipsoide similarity
-        X += -168.0;
-        Y += -60.0;
-        Z += 320.0;
-        // WGS84 cartesian => WGS84 geographic
-        return Geographic(X, Y, Z, Ellipsoid.GRS80);
+    private LatLon NTF_to_WGS84(LatLon ntf) {
+        NTV2GridShift gs = new NTV2GridShift(ntf);
+        if (ntf_rgf93Grid != null) {
+            ntf_rgf93Grid.gridShiftForward(gs);
+            return new LatLon(ntf.lat()+gs.getLatShiftDegrees(), ntf.lon()+gs.getLonShiftPositiveEastDegrees());
+        }
+        return new LatLon(0,0);
     }
 
+    public Bounds getWorldBoundsLatLon()
+    {
+        Bounds b= new Bounds(
+                new LatLon(zoneLimitsDegree[layoutZone][1] - cMaxOverlappingZonesDegree, -4.9074074074074059),
+                new LatLon(zoneLimitsDegree[layoutZone][0] + cMaxOverlappingZonesDegree, 10.2));
+        return b;
+    }
+
     /**
-     * initializes from cartesian coordinates
-     *
-     * @param X
-     *            1st coordinate in meters
-     * @param Y
-     *            2nd coordinate in meters
-     * @param Z
-     *            3rd coordinate in meters
-     * @param ell
-     *            reference ellipsoid
+     * Returns the default zoom scale in pixel per degree ({@see #NavigatableComponent#scale}))
      */
-    private LatLon Geographic(double X, double Y, double Z, Ellipsoid ell) {
-        double norm = Math.sqrt(X * X + Y * Y);
-        double lg = 2.0 * Math.atan(Y / (X + norm));
-        double lt = Math.atan(Z / (norm * (1.0 - (ell.a * ell.e2 / Math.sqrt(X * X + Y * Y + Z * Z)))));
-        double delta = 1.0;
-        while (delta > epsilon) {
-            double s2 = Math.sin(lt);
-            s2 *= s2;
-            double l = Math.atan((Z / norm)
-                    / (1.0 - (ell.a * ell.e2 * Math.cos(lt) / (norm * Math.sqrt(1.0 - ell.e2 * s2)))));
-            delta = Math.abs(l - lt);
-            lt = l;
-        }
-        double s2 = Math.sin(lt);
-        s2 *= s2;
-        // h = norm / Math.cos(lt) - ell.a / Math.sqrt(1.0 - ell.e2 * s2);
-        return new LatLon(lt, lg);
+    public double getDefaultZoomInPPD() {
+        // this will set the map scaler to about 1000 m (in default scale, 1 pixel will be 10 meters)
+        return 10.0;
     }
 
-    private boolean farawayFromLambertZoneFrance(double lat, double lon) {
-        if (lat < (zoneLimits[3] - cMaxOverlappingZones) || (lat > (cMaxLatZone1 + cMaxOverlappingZones))
-                || (lon < (cMinLonZones - cMaxOverlappingZones)) || (lon > (cMaxLonZones + cMaxOverlappingZones)))
-            return true;
-        return false;
+    public int getLayoutZone() {
+        return layoutZone;
     }
 
-    public Bounds getWorldBoundsLatLon()
-    {
-        // These are not the Lambert Zone boundaries but we keep these values until coordinates outside the
-        // projection boundaries are handled correctly.
-        return new Bounds(
-                new LatLon(-85.05112877980659, -180.0),
-                new LatLon(85.05112877980659, 180.0));
-        /*return new Bounds(
-                new LatLon(45.0, -4.9074074074074059),
-                new LatLon(57.0, 10.2));*/
+    public static String[] lambert4zones = { "1 (51.30 to 48.15 degrees)",
+        "2 (48.15 to 45.45 degrees)",
+        "3 (45.45 to 42.76 degrees)",
+    "4 (Corsica)" };
+
+    public void setupPreferencePanel(JPanel p) {
+        JComboBox prefcb = new JComboBox(lambert4zones);
+
+        prefcb.setSelectedIndex(layoutZone);
+        p.setLayout(new GridBagLayout());
+        p.add(new JLabel(tr("Lambert CC Zone")), GBC.std().insets(5,5,0,5));
+        p.add(GBC.glue(1, 0), GBC.std().fill(GBC.HORIZONTAL));
+        /* Note: we use component position 2 below to find this again */
+        p.add(prefcb, GBC.eop().fill(GBC.HORIZONTAL));
+        p.add(GBC.glue(1, 1), GBC.eol().fill(GBC.BOTH));
     }
 
-    public double getDefaultZoomInPPD() {
-        // TODO FIXME
-        return 0;
+    public Collection<String> getPreferences(JPanel p) {
+        Object prefcb = p.getComponent(2);
+        if(!(prefcb instanceof JComboBox))
+            return null;
+        layoutZone = ((JComboBox)prefcb).getSelectedIndex();
+        System.out.println("Current Lambert 4 zone:" + (layoutZone+1));
+        return Collections.singleton(Integer.toString(layoutZone+1));
     }
+
+    public void setPreferences(Collection<String> args) {
+        layoutZone = DEFAULT_ZONE;
+        if (args != null) {
+            try {
+                for(String s : args)
+                {
+                    layoutZone = Integer.parseInt(s)-1;
+                    if(layoutZone < 0 || layoutZone > 3) {
+                        layoutZone = DEFAULT_ZONE;
+                    }
+                    break;
+                }
+            } catch(NumberFormatException e) {}
+        }
+        System.out.println("Current Lambert 4 zone:" + (layoutZone+1));
+    }
+
+    public Collection<String> getPreferencesFromCode(String code) {
+        if (code.startsWith("EPSG:2756") && code.length() == 9) {
+            try {
+                String zonestring = code.substring(9);
+                int zoneval = Integer.parseInt(zonestring);
+                if(zoneval >= 1 && zoneval <= 4)
+                    return Collections.singleton(zonestring);
+            } catch(NumberFormatException e) {}
+        }
+        return null;
+    }
+
 }
Index: LambertCC9Zones.java
===================================================================
--- LambertCC9Zones.java	(revision 2500)
+++ LambertCC9Zones.java	(working copy)
@@ -3,14 +3,21 @@
 
 import static org.openstreetmap.josm.tools.I18n.tr;
 
-import javax.swing.JOptionPane;
+import java.awt.GridBagLayout;
+import java.util.Collection;
+import java.util.Collections;
 
-import org.openstreetmap.josm.Main;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+
 import org.openstreetmap.josm.data.Bounds;
 import org.openstreetmap.josm.data.coor.EastNorth;
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.projection.Projection;
 import org.openstreetmap.josm.data.projection.Ellipsoid;
+import org.openstreetmap.josm.tools.GBC;
+import org.openstreetmap.josm.tools.ImageProvider;
 
 /**
  * This class implements the Lambert Conic Conform 9 Zones projection as specified by the IGN
@@ -18,7 +25,7 @@
  * @author Pieren
  *
  */
-public class LambertCC9Zones implements Projection {
+public class LambertCC9Zones implements Projection, ProjectionSubPrefs {
 
     /**
      * Lambert 9 zones projection exponents
@@ -57,25 +64,26 @@
     /**
      * France is divided in 9 Lambert projection zones, CC42 to CC50.
      */
-    public static final double cMaxLatZones = Math.toRadians(51.1);
+    public static final double cMaxLatZonesRadian = Math.toRadians(51.1);
 
-    public static final double cMinLatZones = Math.toRadians(41.0);
+    public static final double cMinLatZonesDegree = 41.0;
+    public static final double cMinLatZonesRadian = Math.toRadians(cMinLatZonesDegree);
 
-    public static final double cMinLonZones = Math.toRadians(-5.0);
+    public static final double cMinLonZonesRadian = Math.toRadians(-5.0);
 
-    public static final double cMaxLonZones = Math.toRadians(10.2);
+    public static final double cMaxLonZonesRadian = Math.toRadians(10.2);
 
     public static final double lambda0 = Math.toRadians(3);
     public static final double e = Ellipsoid.GRS80.e; // but in doc=0.08181919112
     public static final double e2 =Ellipsoid.GRS80.e2;
     public static final double a = Ellipsoid.GRS80.a;
-    /**
-     *  Because josm cannot work correctly if two zones are displayed, we allow some overlapping
-     */
-    public static final double cMaxOverlappingZones = Math.toRadians(1.5);
 
-    public static int layoutZone = -1;
+    public static final double cMaxOverlappingZones = 1.5;
 
+    public static final int DEFAULT_ZONE = 0;
+
+    private static int layoutZone = DEFAULT_ZONE;
+
     private double L(double phi, double e) {
         double sinphi = Math.sin(phi);
         return (0.5*Math.log((1+sinphi)/(1-sinphi))) - e/2*Math.log((1+e*sinphi)/(1-e*sinphi));
@@ -88,49 +96,9 @@
     public EastNorth latlon2eastNorth(LatLon p) {
         double lt = Math.toRadians(p.lat());
         double lg = Math.toRadians(p.lon());
-        // check if longitude and latitude are inside the French Lambert zones and seek a zone number
-        // if it is not already defined in layoutZone
-        int possibleZone = 0;
-        boolean outOfLambertZones = false;
-        if (lt >= cMinLatZones && lt <= cMaxLatZones && lg >= cMinLonZones && lg <= cMaxLonZones) {
-            /* with Lambert CC9 zones, each latitude is present in two zones. If the layout
-               zone is not already set, we choose arbitrary the first possible zone */
-            possibleZone = (int)p.lat()-42;
-            if (possibleZone > 8) {
-                possibleZone = 8;
-            }
-            if (possibleZone < 0) {
-                possibleZone = 0;
-            }
-        } else {
-            outOfLambertZones = true; // possible when MAX_LAT is used
-        }
-        if (!outOfLambertZones) {
-            if (layoutZone == -1) {
-                if (layoutZone != possibleZone) {
-                    System.out.println("change Lambert zone from "+layoutZone+" to "+possibleZone);
-                }
-                layoutZone = possibleZone;
-            } else if (Math.abs(layoutZone - possibleZone) > 1) {
-                if (farawayFromLambertZoneFrance(lt, lg)) {
-                    JOptionPane.showMessageDialog(Main.parent,
-                            tr("IMPORTANT : data positioned far away from\n"
-                                    + "the current Lambert zone limits.\n"
-                                    + "Do not upload any data after this message.\n"
-                                    + "Undo your last action, save your work\n"
-                                    + "and start a new layer on the new zone."),
-                                    tr("Warning"),
-                                    JOptionPane.WARNING_MESSAGE);
-                    layoutZone = -1;
-                } else {
-                    System.out.println("temporarily extend Lambert zone " + layoutZone + " projection at lat,lon:"
-                            + lt + "," + lg);
-                }
-            }
-        }
-        if (layoutZone == -1)
-            return ConicProjection(lt, lg, possibleZone);
-        return ConicProjection(lt, lg, layoutZone);
+        if (lt >= cMinLatZonesRadian && lt <= cMaxLatZonesRadian && lg >= cMinLonZonesRadian && lg <= cMaxLonZonesRadian)
+            return ConicProjection(lt, lg, layoutZone);
+        return ConicProjection(lt, lg, 0);
     }
 
     /**
@@ -149,7 +117,6 @@
     }
 
     public LatLon eastNorth2latlon(EastNorth p) {
-        layoutZone  = north2ZoneNumber(p.north());
         return Geographic(p, layoutZone);
     }
 
@@ -173,47 +140,98 @@
         else return nz;
     }
 
-    public static boolean isInL9CCZones(LatLon p) {
-        double lt = Math.toRadians(p.lat());
-        double lg = Math.toRadians(p.lon());
-        if (lg >= cMinLonZones && lg <= cMaxLonZones && lt >= cMinLatZones && lt <= cMaxLatZones)
-            return true;
-        return false;
-    }
-
     public String toCode() {
-        if (layoutZone == -1)
-            return "EPSG:"+(3942);
-        return "EPSG:"+(3942+layoutZone); //CC42 is EPSG:3842 (up to EPSG:3950 for CC50)
+        return "EPSG:"+(3942+layoutZone); //CC42 is EPSG:3942 (up to EPSG:3950 for CC50)
     }
 
     public String getCacheDirectoryName() {
         return "lambert";
     }
 
-    private boolean farawayFromLambertZoneFrance(double lat, double lon) {
-        if (lat < (cMinLatZones - cMaxOverlappingZones) || (lat > (cMaxLatZones + cMaxOverlappingZones))
-                || (lon < (cMinLonZones - cMaxOverlappingZones)) || (lon > (cMaxLonZones + cMaxOverlappingZones)))
-            return true;
-        return false;
-    }
-
+    /**
+     * Returns the default zoom scale in pixel per degree ({@see #NavigatableComponent#scale}))
+     */
     public double getDefaultZoomInPPD() {
-        // TODO Auto-generated method stub
-        return 0;
+        // this will set the map scaler to about 1000 m (in default scale, 1 pixel will be 10 meters)
+        return 10.0;
     }
 
     public Bounds getWorldBoundsLatLon()
     {
-        // These are not the Lambert Zone boundaries but we keep these values until coordinates outside the
-        // projection boundaries are handled correctly.
+        double medLatZone = cMinLatZonesDegree + (layoutZone+1);
         return new Bounds(
-                new LatLon(-85.05112877980659, -180.0),
-                new LatLon(85.05112877980659, 180.0));
-        /*return new Bounds(
-                new LatLon(45.0, -4.9074074074074059),
-                new LatLon(57.0, 10.2));*/
+                new LatLon(medLatZone - 1.0 - cMaxOverlappingZones, -4.9),
+                new LatLon(medLatZone + 1.0 + cMaxOverlappingZones, 10.2));
     }
 
+    public int getLayoutZone() {
+        return layoutZone;
+    }
+
+    private static String[] lambert9zones = { "1 (41 to 43 degrees)", "2 (42 to 44 degrees)",
+        "3 (43 to 45 degrees)", "4 (44 to 46 degrees)", "5 (45 to 47 degrees)",
+        "6 (46 to 48 degrees)", "7 (47 to 49 degrees)", "8 (48 to 50 degrees)",
+    "9 (49 to 51 degrees)" };
+
+    public void setupPreferencePanel(JPanel p) {
+        JComboBox prefcb = new JComboBox(lambert9zones);
+
+        prefcb.setSelectedIndex(layoutZone);
+        p.setLayout(new GridBagLayout());
+        p.add(new JLabel(tr("Lambert CC Zone")), GBC.std().insets(5,5,0,5));
+        p.add(GBC.glue(1, 0), GBC.std().fill(GBC.HORIZONTAL));
+        /* Note: we use component position 2 below to find this again */
+        p.add(prefcb, GBC.eop().fill(GBC.HORIZONTAL));
+        p.add(new JLabel(ImageProvider.get("data/projection", "LambertCC9Zones.png")), GBC.eol().fill(GBC.HORIZONTAL));
+        p.add(GBC.glue(1, 1), GBC.eol().fill(GBC.BOTH));
+    }
+
+    public Collection<String> getPreferences(JPanel p) {
+        Object prefcb = p.getComponent(2);
+        if(!(prefcb instanceof JComboBox))
+            return null;
+        layoutZone = ((JComboBox)prefcb).getSelectedIndex();
+        System.out.println("Current Lambert CC 9 zone:" + (layoutZone+1));
+        if (layoutZone == 0) {
+            layoutZone = layoutZone +1 -1;
+        }
+        return Collections.singleton(Integer.toString(layoutZone+1));
+    }
+
+    public void setPreferences(Collection<String> args)
+    {
+        layoutZone = DEFAULT_ZONE;
+        if (args != null) {
+            try {
+                for(String s : args)
+                {
+                    layoutZone = Integer.parseInt(s)-1;
+                    if(layoutZone < 0 || layoutZone > 8) {
+                        layoutZone = DEFAULT_ZONE;
+                    }
+                    break;
+                }
+            } catch(NumberFormatException e) {}
+        }
+        System.out.println("Current Lambert CC 9 zone:" + (layoutZone+1));
+        if (layoutZone == 0) {
+            layoutZone = layoutZone +1 -1;
+        }
+    }
+
+    public Collection<String> getPreferencesFromCode(String code)
+    {
+        //zone 1=CC42=EPSG:3942 up to zone 9=CC50=EPSG:3950
+        if (code.startsWith("EPSG:39") && code.length() == 9) {
+            try {
+                String zonestring = code.substring(5,4);
+                int zoneval = Integer.parseInt(zonestring)-3942;
+                if(zoneval >= 0 && zoneval <= 8)
+                    return Collections.singleton(zonestring);
+            } catch(NumberFormatException e) {}
+        }
+        return null;
+    }
+
 }
 
Index: Projection.java
===================================================================
--- Projection.java	(revision 2500)
+++ Projection.java	(working copy)
@@ -27,9 +27,7 @@
         new Lambert(),    // Still needs proper default zoom
         new SwissGrid(),
         new UTM(),
-        new UTM_20N_Guadeloupe_Ste_Anne(),
-        new UTM_20N_Guadeloupe_Fort_Marigot(),
-        new UTM_20N_Martinique_Fort_Desaix(),
+        new UTM_20N_France_DOM(),
         new GaussLaborde_Reunion(),
         new LambertCC9Zones()    // Still needs proper default zoom
     };
Index: UTM_20N_France_DOM.java
===================================================================
--- UTM_20N_France_DOM.java	(revision 2500)
+++ UTM_20N_France_DOM.java	(working copy)
@@ -2,15 +2,41 @@
 package org.openstreetmap.josm.data.projection;
 
 /**
- * This class is not a direct implementation of Projection. It collects all methods used
- * for the projection of the French departements in the Caribbean Sea UTM zone 20N
- * but using each time different local geodesic settings for the 7 parameters transformation algorithm.
+ * This class implements all projections for French departements in the Caribbean Sea using
+ * UTM zone 20N transvers Mercator and specific geodesic settings (7 parameters transformation algorithm).
  */
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.GridBagLayout;
+import java.util.Collection;
+import java.util.Collections;
+
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+
+import org.openstreetmap.josm.data.Bounds;
 import org.openstreetmap.josm.data.coor.EastNorth;
 import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.tools.GBC;
 
-public class UTM_20N_France_DOM {
+public class UTM_20N_France_DOM implements Projection, ProjectionSubPrefs {
 
+    private static String FortMarigotName = tr("Guadeloupe Fort-Marigot 1949");
+    private static String SainteAnneName = tr("Guadeloupe Ste-Anne 1948");
+    private static String MartiniqueName = tr("Martinique Fort Desaix 1952");
+    public static String[] utmGeodesicsNames = { FortMarigotName, SainteAnneName, MartiniqueName};
+
+    private Bounds FortMarigotBounds = new Bounds( new LatLon(17.6,-63.25), new LatLon(18.5,-62.5));
+    private Bounds SainteAnneBounds = new Bounds( new LatLon(15.8,-61.9), new LatLon(16.6,-60.9));
+    private Bounds MartiniqueBounds = new Bounds( new LatLon(14.25,-61.25), new LatLon(15.025,-60.725));
+    private Bounds[] utmBounds = { FortMarigotBounds, SainteAnneBounds, MartiniqueBounds};
+
+    private String FortMarigotEPSG = "EPSG::2969";
+    private String SainteAnneEPSG = "EPSG::2970";
+    private String MartiniqueEPSG = "EPSG::2973";
+    private String[] utmEPSGs = { FortMarigotEPSG, SainteAnneEPSG, MartiniqueEPSG};
+
     /**
      * false east in meters (constant)
      */
@@ -27,21 +53,26 @@
     /**
      * UTM zone (from 1 to 60)
      */
-    int zone = 20;
+    private static int ZONE = 20;
     /**
      * whether north or south hemisphere
      */
     private boolean isNorth = true;
+
+    public static final int DEFAULT_GEODESIC = 0;
+
+    private static int currentGeodesic = DEFAULT_GEODESIC;
+
     /**
      * 7 parameters transformation
      */
-    double tx = 0.0;
-    double ty = 0.0;
-    double tz = 0.0;
-    double rx = 0;
-    double ry = 0;
-    double rz = 0;
-    double scaleDiff = 0;
+    private static double tx = 0.0;
+    private static double ty = 0.0;
+    private static double tz = 0.0;
+    private static double rx = 0;
+    private static double ry = 0;
+    private static double rz = 0;
+    private static double scaleDiff = 0;
     /**
      * precision in iterative schema
      */
@@ -49,15 +80,33 @@
     public final static double DEG_TO_RAD = Math.PI / 180;
     public final static double RAD_TO_DEG = 180 / Math.PI;
 
-    public UTM_20N_France_DOM(double[] translation, double[] rotation, double scaleDiff) {
-        this.tx = translation[0];
-        this.ty = translation[1];
-        this.tz = translation[2];
-        this.rx = rotation[0]/206264.806247096355; // seconds to radian
-        this.ry = rotation[1]/206264.806247096355;
-        this.rz = rotation[2]/206264.806247096355;
-        this.scaleDiff = scaleDiff;
+    private void refresh7ParametersTranslation() {
+        System.out.println("Current UTM geodesic system: " + utmGeodesicsNames[currentGeodesic]);
+        if (currentGeodesic == 0) { // UTM_20N_Guadeloupe_Fort_Marigot
+            set7ParametersTranslation(new double[]{136.596, 248.148, -429.789},
+                    new double[]{0, 0, 0},
+                    0);
+        } else if (currentGeodesic == 1) { // UTM_20N_Guadeloupe_Ste_Anne
+            set7ParametersTranslation(new double[]{-472.29, -5.63, -304.12},
+                    new double[]{0.4362, -0.8374, 0.2563},
+                    1.8984E-6);
+        } else { // UTM_20N_Martinique_Fort_Desaix
+            set7ParametersTranslation(new double[]{126.926, 547.939, 130.409},
+                    new double[]{-2.78670, 5.16124,  -0.85844},
+                    13.82265E-6);
+        }
     }
+
+    private void set7ParametersTranslation(double[] translation, double[] rotation, double scalediff) {
+        tx = translation[0];
+        ty = translation[1];
+        tz = translation[2];
+        rx = rotation[0]/206264.806247096355; // seconds to radian
+        ry = rotation[1]/206264.806247096355;
+        rz = rotation[2]/206264.806247096355;
+        scaleDiff = scalediff;
+    }
+
     public EastNorth latlon2eastNorth(LatLon p) {
         // translate ellipsoid GRS80 (WGS83) => reference ellipsoid geographic
         LatLon geo = GRS802Hayford(p);
@@ -127,7 +176,7 @@
         Ys = (coord.lat() >= 0.0) ? 0.0 : 10000000.0;
         double r6d = Math.PI / 30.0;
         //zone = (int) Math.floor((coord.lon() + Math.PI) / r6d) + 1;
-        lg0 = r6d * (zone - 0.5) - Math.PI;
+        lg0 = r6d * (ZONE - 0.5) - Math.PI;
         double e2 = e * e;
         double e4 = e2 * e2;
         double e6 = e4 * e2;
@@ -168,11 +217,10 @@
     }
 
     public LatLon eastNorth2latlon(EastNorth p) {
-        MTProjection(p.east(), p.north(), zone, isNorth);
+        MTProjection(p.east(), p.north(), ZONE, isNorth);
         LatLon geo = Geographic(p, Ellipsoid.hayford.a, Ellipsoid.hayford.e, 0.0 /* z */);
 
         // reference ellipsoid geographic => reference ellipsoid cartesian
-        //Hayford2GRS80(ellipsoid, geo);
         double N = Ellipsoid.hayford.a / (Math.sqrt(1.0 - Ellipsoid.hayford.e2 * Math.sin(geo.lat()) * Math.sin(geo.lat())));
         double X = (N /*+ h*/) * Math.cos(geo.lat()) * Math.cos(geo.lon());
         double Y = (N /*+ h*/) * Math.cos(geo.lat()) * Math.sin(geo.lon());
@@ -309,4 +357,76 @@
         return new double[]{Xb, Yb, Zb};
     }
 
+    public String getCacheDirectoryName() {
+        return this.toString();
+    }
+
+    /**
+     * Returns the default zoom scale in pixel per degree ({@see #NavigatableComponent#scale}))
+     */
+    public double getDefaultZoomInPPD() {
+        // this will set the map scaler to about 1000 m (in default scale, 1 pixel will be 10 meters)
+        return 10.0;
+    }
+
+    public Bounds getWorldBoundsLatLon() {
+        return utmBounds[currentGeodesic];
+    }
+
+    public String toCode() {
+        return utmEPSGs[currentGeodesic];
+    }
+
+    @Override public String toString() {
+        return (tr("UTM 20N (France)"));
+    }
+
+    public int getCurrentGeodesic() {
+        return currentGeodesic;
+    }
+
+    public void setupPreferencePanel(JPanel p) {
+        JComboBox prefcb = new JComboBox(utmGeodesicsNames);
+
+        prefcb.setSelectedIndex(currentGeodesic);
+        p.setLayout(new GridBagLayout());
+        p.add(new JLabel(tr("UTM20 North Geodesic system")), GBC.std().insets(5,5,0,5));
+        p.add(GBC.glue(1, 0), GBC.std().fill(GBC.HORIZONTAL));
+        p.add(prefcb, GBC.eop().fill(GBC.HORIZONTAL));
+        p.add(GBC.glue(1, 1), GBC.eol().fill(GBC.BOTH));
+    }
+
+    public Collection<String> getPreferences(JPanel p) {
+        Object prefcb = p.getComponent(2);
+        if(!(prefcb instanceof JComboBox))
+            return null;
+        currentGeodesic = ((JComboBox)prefcb).getSelectedIndex();
+        refresh7ParametersTranslation();
+        return Collections.singleton(Integer.toString(currentGeodesic+1));
+    }
+
+    public Collection<String> getPreferencesFromCode(String code) {
+        for (int i=0; i < utmEPSGs.length; i++ )
+            if (utmEPSGs[i].endsWith(code))
+                return Collections.singleton(Integer.toString(i));
+        return null;
+    }
+
+    public void setPreferences(Collection<String> args) {
+        currentGeodesic = DEFAULT_GEODESIC;
+        if (args != null) {
+            try {
+                for(String s : args)
+                {
+                    currentGeodesic = Integer.parseInt(s)-1;
+                    if(currentGeodesic < 0 || currentGeodesic > 2) {
+                        currentGeodesic = DEFAULT_GEODESIC;
+                    }
+                    break;
+                }
+            } catch(NumberFormatException e) {}
+        }
+        refresh7ParametersTranslation();
+    }
+
 }
