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 }