001    //License: GPL. For details, see LICENSE file.
002    package org.openstreetmap.josm.data.projection;
003    
004    import static org.openstreetmap.josm.tools.I18n.tr;
005    
006    import org.openstreetmap.josm.data.Bounds;
007    import org.openstreetmap.josm.data.coor.LatLon;
008    import org.openstreetmap.josm.data.projection.datum.GRS80Datum;
009    import org.openstreetmap.josm.data.projection.proj.LambertConformalConic;
010    import org.openstreetmap.josm.data.projection.proj.ProjParameters;
011    
012    /**
013     * Lambert Conic Conform 9 Zones projection as specified by the IGN
014     * in this document http://professionnels.ign.fr/DISPLAY/000/526/700/5267002/transformation.pdf
015     * @author Pieren
016     *
017     */
018    public class LambertCC9Zones extends AbstractProjection {
019    
020        /**
021         * France is divided in 9 Lambert projection zones, CC42 to CC50.
022         */
023        public static final double cMaxLatZonesRadian = Math.toRadians(51.1);
024    
025        public static final double cMinLatZonesDegree = 41.0;
026    
027        public static final double cMaxOverlappingZones = 1.5;
028    
029        public static final int DEFAULT_ZONE = 0;
030    
031        private final int layoutZone;
032    
033        public LambertCC9Zones() {
034            this(DEFAULT_ZONE);
035        }
036    
037        public LambertCC9Zones(final int layoutZone) {
038            ellps = Ellipsoid.GRS80;
039            datum = GRS80Datum.INSTANCE;
040            this.layoutZone = layoutZone;
041            x_0 = 1700000;
042            y_0 = (layoutZone+1) * 1000000 + 200000;
043            lon_0 = 3;
044            if (proj == null) {
045                proj = new LambertConformalConic();
046            }
047            try {
048                proj.initialize(new ProjParameters() {{
049                    ellps = LambertCC9Zones.this.ellps;
050                    lat_0 = 42.0 + layoutZone;
051                    lat_1 = 41.25 + layoutZone;
052                    lat_2 = 42.75 + layoutZone;
053                }});
054            } catch (ProjectionConfigurationException e) {
055                throw new RuntimeException(e);
056            }
057        }
058    
059        @Override
060        public String toString() {
061            return tr("Lambert CC9 Zone (France)");
062        }
063    
064        public static int north2ZoneNumber(double north) {
065            int nz = (int)(north /1000000) - 1;
066            if (nz < 0) return 0;
067            else if (nz > 8) return 8;
068            else return nz;
069        }
070    
071        @Override
072        public Integer getEpsgCode() {
073            return 3942+layoutZone; //CC42 is EPSG:3942 (up to EPSG:3950 for CC50)
074        }
075    
076        @Override
077        public int hashCode() {
078            return getClass().getName().hashCode()+layoutZone; // our only real variable
079        }
080    
081        @Override
082        public String getCacheDirectoryName() {
083            return "lambert";
084        }
085    
086        @Override
087        public Bounds getWorldBoundsLatLon()
088        {
089            double medLatZone = cMinLatZonesDegree + (layoutZone+1);
090            return new Bounds(
091                    new LatLon(Math.max(medLatZone - 1.0 - cMaxOverlappingZones, cMinLatZonesDegree), -5.5),
092                    new LatLon(Math.min(medLatZone + 1.0 + cMaxOverlappingZones, Math.toDegrees(cMaxLatZonesRadian)), 10.2),
093                    false);
094        }
095    
096        public int getLayoutZone() {
097            return layoutZone;
098        }
099    
100    }