// License: GPL. For details, see LICENSE file. import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.openstreetmap.josm.data.projection.CustomProjection; import org.openstreetmap.josm.data.projection.ProjectionConfigurationException; import org.openstreetmap.josm.data.projection.Projections; import org.openstreetmap.josm.data.projection.Projections.ProjectionDefinition; import org.openstreetmap.josm.data.projection.proj.Proj; /** * Generates the list of projections by combining two sources: The list from the * proj.4 project and a list maintained by the JOSM team. */ public class BuildProjectionDefinitions { private static final String JOSM_EPSG_FILE = "data_nodist/projection/josm-epsg"; private static final String PROJ4_EPSG_FILE = "data_nodist/projection/epsg"; private static final String OUTPUT_EPSG_FILE = "data/projection/custom-epsg"; private static final Map epsgProj4 = new LinkedHashMap<>(); private static final Map epsgJosm = new LinkedHashMap<>(); private static final boolean printStats = false; // statistics: private static int noInJosm = 0; private static int noDeprecated = 0; private static int noGeocent = 0; private static int noBaseProjection = 0; private static final Map baseProjectionMap = new HashMap<>(); private static int noDatumgrid = 0; private static int noJosm = 0; private static int noProj4 = 0; private static int noOmercNoBounds = 0; /** * Program entry point * @param args command line arguments (not used) * @throws IOException if any I/O error occurs */ public static void main(String[] args) throws IOException { buildList(args[0]); } static void buildList(String baseDir) throws IOException { List pdJosm = Projections.loadProjectionDefinitions(baseDir + File.separator + JOSM_EPSG_FILE); for (ProjectionDefinition pd : pdJosm) { epsgJosm.put(pd.code, pd); } List pdProj4 = Projections.loadProjectionDefinitions(baseDir + File.separator + PROJ4_EPSG_FILE); for (ProjectionDefinition pd : pdProj4) { epsgProj4.put(pd.code, pd); } try (FileOutputStream output = new FileOutputStream(baseDir + File.separator + OUTPUT_EPSG_FILE); BufferedWriter out = new BufferedWriter(new OutputStreamWriter(output, StandardCharsets.UTF_8))) { out.write("## This file is autogenerated, do not edit!\n"); out.write("## Run ant task \"epsg\" to rebuild.\n"); out.write(String.format("## Source files are %s (can be changed) and %s (copied from the proj.4 project).%n", JOSM_EPSG_FILE, PROJ4_EPSG_FILE)); out.write("##\n"); out.write("## Entries checked and maintained by the JOSM team:\n"); for (ProjectionDefinition pd : epsgJosm.values()) { write(out, pd); noJosm++; } out.write("## Other supported projections (source: proj.4):\n"); for (ProjectionDefinition pd : epsgProj4.values()) { if (doInclude(pd, true)) { write(out, pd); noProj4++; } } } if (printStats) { System.out.println(String.format("loaded %d entries from %s", epsgJosm.size(), JOSM_EPSG_FILE)); System.out.println(String.format("loaded %d entries from %s", epsgProj4.size(), PROJ4_EPSG_FILE)); System.out.println(); System.out.println("some entries from proj.4 have not been included:"); System.out.println(String.format(" * already in the maintained JOSM list: %d entries", noInJosm)); System.out.println(String.format(" * deprecated: %d entries", noDeprecated)); System.out.println(String.format(" * using +proj=geocent, which is 3D (X,Y,Z) and not useful in JOSM: %d entries", noGeocent)); System.out.println(String.format(" * unsupported base projection: %d entries", noBaseProjection)); System.out.println(" in particular: " + baseProjectionMap); System.out.println(String.format(" * requires data file for datum conversion: %d entries", noDatumgrid)); if (noOmercNoBounds > 0) { System.out.println(String.format(" * projection is Oblique Mercator (requires bounds), but no bounds specified: %d entries", noOmercNoBounds)); } System.out.println(); System.out.println(String.format("written %d entries from %s", noJosm, JOSM_EPSG_FILE)); System.out.println(String.format("written %d entries from %s", noProj4, PROJ4_EPSG_FILE)); } } static void write(BufferedWriter out, ProjectionDefinition pd) throws IOException { out.write("# " + pd.name + "\n"); out.write("<"+pd.code.substring("EPSG:".length())+"> "+pd.definition+" <>\n"); } static boolean doInclude(ProjectionDefinition pd, boolean noIncludeJosm) { boolean result = true; if (noIncludeJosm) { // we already have this projection if (epsgJosm.containsKey(pd.code)) { result = false; noInJosm++; } } // exclude deprecated projections // EPSG:4296 is also deprecated, but this is not mentioned in the name if (pd.name.contains("deprecated") || pd.code.equals("EPSG:4296")) { result = false; noDeprecated++; } Map parameters; try { parameters = CustomProjection.parseParameterList(pd.definition, true); } catch (ProjectionConfigurationException ex) { throw new RuntimeException(pd.code+":"+ex); } String proj = parameters.get(CustomProjection.Param.proj.key); // +proj=geocent is 3D (X,Y,Z) "projection" - this is not useful in // JOSM as we only deal with 2D maps if ("geocent".equals(proj)) { result = false; noGeocent++; } // no support for NAD27 datum, as it requires a conversion database String datum = parameters.get(CustomProjection.Param.datum.key); if ("NAD27".equals(datum)) { result = false; noDatumgrid++; } // requires datum conversion database if (parameters.containsKey("geoidgrids")) { result = false; noDatumgrid++; } // exclude entries where we don't support the base projection Proj bp = Projections.getBaseProjection(proj); if (result && !"utm".equals(proj) && bp == null) { result = false; noBaseProjection++; if (!"geocent".equals(proj)) { if (!baseProjectionMap.containsKey(proj)) { baseProjectionMap.put(proj, 0); } baseProjectionMap.put(proj, baseProjectionMap.get(proj)+1); } } if (result && "omerc".equals(proj) && !parameters.containsKey(CustomProjection.Param.bounds.key)) { result = false; noOmercNoBounds++; } return result; } }