Changeset 13598 in josm
- Timestamp:
- 2018-04-05T19:03:04+02:00 (7 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/CONTRIBUTION
r13588 r13598 93 93 Swiss CHENYX06 NTV2 grid: Source: Swiss Federal Office of Topography 94 94 95 ESRI projection definitions: Environmental Systems Research Institute 96 95 97 ------------------------------------ ICONS ------------------------------------ 96 98 -
trunk/scripts/BuildProjectionDefinitions.java
r13583 r13598 7 7 import java.io.OutputStreamWriter; 8 8 import java.nio.charset.StandardCharsets; 9 import java.util. HashMap;9 import java.util.Arrays; 10 10 import java.util.LinkedHashMap; 11 import java.util.List; 12 import java.util.Locale; 11 13 import java.util.Map; 14 import java.util.TreeMap; 12 15 13 16 import org.openstreetmap.josm.data.projection.CustomProjection; 17 import org.openstreetmap.josm.data.projection.CustomProjection.Param; 14 18 import org.openstreetmap.josm.data.projection.ProjectionConfigurationException; 15 19 import org.openstreetmap.josm.data.projection.Projections; … … 23 27 public class BuildProjectionDefinitions { 24 28 25 private static final String JOSM_EPSG_FILE = "data_nodist/projection/josm-epsg"; 26 private static final String PROJ4_EPSG_FILE = "data_nodist/projection/epsg"; 27 private static final String PROJ4_ESRI_FILE = "data_nodist/projection/esri"; 29 private static final String PROJ_DIR = "data_nodist/projection"; 30 private static final String JOSM_EPSG_FILE = "josm-epsg"; 31 private static final String PROJ4_EPSG_FILE = "epsg"; 32 private static final String PROJ4_ESRI_FILE = "esri"; 28 33 private static final String OUTPUT_EPSG_FILE = "data/projection/custom-epsg"; 29 34 … … 40 45 private static int noGeocent = 0; 41 46 private static int noBaseProjection = 0; 42 private static final Map<String, Integer> baseProjectionMap = new HashMap<>(); 47 private static int noEllipsoid = 0; 48 private static int noNadgrid = 0; 43 49 private static int noDatumgrid = 0; 44 50 private static int noJosm = 0; … … 47 53 private static int noOmercNoBounds = 0; 48 54 private static int noEquatorStereo = 0; 55 56 private static final Map<String, Integer> baseProjectionMap = new TreeMap<>(); 57 private static final Map<String, Integer> ellipsoidMap = new TreeMap<>(); 58 private static final Map<String, Integer> nadgridMap = new TreeMap<>(); 59 private static final Map<String, Integer> datumgridMap = new TreeMap<>(); 60 61 private static List<String> knownGeoidgrids; 62 private static List<String> knownNadgrids; 49 63 50 64 /** … … 57 71 } 58 72 73 static List<String> initList(String baseDir, String ext) { 74 return Arrays.asList(new File(baseDir + File.separator + PROJ_DIR) 75 .list((dir, name) -> !name.contains(".") || name.toLowerCase(Locale.ENGLISH).endsWith(ext))); 76 } 77 59 78 static void initMap(String baseDir, String file, Map<String, ProjectionDefinition> map) throws IOException { 60 for (ProjectionDefinition pd : Projections.loadProjectionDefinitions(baseDir + File.separator + file)) { 79 for (ProjectionDefinition pd : Projections.loadProjectionDefinitions( 80 baseDir + File.separator + PROJ_DIR + File.separator + file)) { 61 81 map.put(pd.code, pd); 62 82 } … … 67 87 initMap(baseDir, PROJ4_EPSG_FILE, epsgProj4); 68 88 initMap(baseDir, PROJ4_ESRI_FILE, esriProj4); 89 90 knownGeoidgrids = initList(baseDir, ".gtx"); 91 knownNadgrids = initList(baseDir, ".gsb"); 69 92 70 93 try (FileOutputStream output = new FileOutputStream(baseDir + File.separator + OUTPUT_EPSG_FILE); … … 104 127 System.out.println("some entries from proj.4 have not been included:"); 105 128 System.out.println(String.format(" * already in the maintained JOSM list: %d entries", noInJosm)); 106 System.out.println(String.format(" * ESRI already in the standard EPSG list: %d entries", noInProj4)); 129 if (noInProj4 > 0) { 130 System.out.println(String.format(" * ESRI already in the standard EPSG list: %d entries", noInProj4)); 131 } 107 132 System.out.println(String.format(" * deprecated: %d entries", noDeprecated)); 108 133 System.out.println(String.format(" * using +proj=geocent, which is 3D (X,Y,Z) and not useful in JOSM: %d entries", noGeocent)); 109 System.out.println(String.format(" * unsupported base projection: %d entries", noBaseProjection)); 110 System.out.println(" in particular: " + baseProjectionMap); 111 System.out.println(String.format(" * requires data file for datum conversion: %d entries", noDatumgrid)); 134 if (noEllipsoid > 0) { 135 System.out.println(String.format(" * unsupported ellipsoids: %d entries", noEllipsoid)); 136 System.out.println(" in particular: " + ellipsoidMap); 137 } 138 if (noBaseProjection > 0) { 139 System.out.println(String.format(" * unsupported base projection: %d entries", noBaseProjection)); 140 System.out.println(" in particular: " + baseProjectionMap); 141 } 142 if (noDatumgrid > 0) { 143 System.out.println(String.format(" * requires data file for vertical datum conversion: %d entries", noDatumgrid)); 144 System.out.println(" in particular: " + datumgridMap); 145 } 146 if (noNadgrid > 0) { 147 System.out.println(String.format(" * requires data file for datum conversion: %d entries", noNadgrid)); 148 System.out.println(" in particular: " + nadgridMap); 149 } 112 150 if (noOmercNoBounds > 0) { 113 151 System.out.println(String.format(" * projection is Oblique Mercator (requires bounds), but no bounds specified: %d entries", noOmercNoBounds)); … … 147 185 } 148 186 149 // exclude deprecated projections 187 // exclude deprecated/discontinued projections 150 188 // EPSG:4296 is also deprecated, but this is not mentioned in the name 151 if (pd.name.contains("deprecated") || pd.code.equals("EPSG:4296")) { 189 String lowName = pd.name.toLowerCase(Locale.ENGLISH); 190 if (lowName.contains("deprecated") || lowName.contains("discontinued") || pd.code.equals("EPSG:4296")) { 152 191 result = false; 153 192 noDeprecated++; … … 176 215 } 177 216 178 // requires datum conversion database 179 if (parameters.containsKey("geoidgrids")) { 217 // requires vertical datum conversion database (.gtx) 218 String geoidgrids = parameters.get("geoidgrids"); 219 if (geoidgrids != null && !"@null".equals(geoidgrids) && !knownGeoidgrids.contains(geoidgrids)) { 180 220 result = false; 181 221 noDatumgrid++; 222 incMap(datumgridMap, geoidgrids); 223 } 224 225 // requires datum conversion database (.gsb) 226 String nadgrids = parameters.get("nadgrids"); 227 if (nadgrids != null && !"@null".equals(nadgrids) && !knownNadgrids.contains(nadgrids)) { 228 result = false; 229 noNadgrid++; 230 incMap(nadgridMap, nadgrids); 182 231 } 183 232 … … 188 237 noBaseProjection++; 189 238 if (!"geocent".equals(proj)) { 190 if (!baseProjectionMap.containsKey(proj)) { 191 baseProjectionMap.put(proj, 0); 239 incMap(baseProjectionMap, proj); 240 } 241 } 242 243 // exclude entries where we don't support the base ellipsoid 244 String ellps = parameters.get("ellps"); 245 if (result && ellps != null && Projections.getEllipsoid(ellps) == null) { 246 result = false; 247 noEllipsoid++; 248 incMap(ellipsoidMap, ellps); 249 } 250 251 if (result && "omerc".equals(proj) && !parameters.containsKey(CustomProjection.Param.bounds.key)) { 252 result = false; 253 noOmercNoBounds++; 254 } 255 256 final double EPS10 = 1.e-10; 257 258 String lat0 = parameters.get("lat_0"); 259 if (lat0 != null) { 260 try { 261 final double latitudeOfOrigin = Math.toRadians(CustomProjection.parseAngle(lat0, Param.lat_0.key)); 262 // TODO: implement equatorial stereographic, see https://josm.openstreetmap.de/ticket/15970 263 if (result && "stere".equals(proj) && Math.abs(latitudeOfOrigin) < EPS10) { 264 result = false; 265 noEquatorStereo++; 192 266 } 193 baseProjectionMap.put(proj, baseProjectionMap.get(proj)+1); 194 } 195 } 196 197 if (result && "omerc".equals(proj) && !parameters.containsKey(CustomProjection.Param.bounds.key)) { 198 result = false; 199 noOmercNoBounds++; 200 } 201 // TODO: implement equatorial stereographic, see https://josm.openstreetmap.de/ticket/15970 202 if (result && "stere".equals(proj) && "0".equals(parameters.get(CustomProjection.Param.lat_0.key))) { 203 result = false; 204 noEquatorStereo++; 267 268 // exclude entries which need geodesic computation (equatorial/oblique azimuthal equidistant) 269 if (result && "aeqd".equals(proj)) { 270 final double HALF_PI = Math.PI / 2; 271 if (Math.abs(latitudeOfOrigin - HALF_PI) >= EPS10 && 272 Math.abs(latitudeOfOrigin + HALF_PI) >= EPS10) { 273 // See https://josm.openstreetmap.de/ticket/16129#comment:21 274 result = false; 275 } 276 } 277 } catch (NumberFormatException | ProjectionConfigurationException e) { 278 e.printStackTrace(); 279 result = false; 280 } 281 } 282 283 if (result && "0.0".equals(parameters.get("rf"))) { 284 // Proj fails with "reciprocal flattening (1/f) = 0" for 285 result = false; // FIXME Only for some projections? 286 } 287 288 String k_0 = parameters.get("k_0"); 289 if (result && k_0 != null && k_0.startsWith("-")) { 290 // Proj fails with "k <= 0" for ESRI:102470 291 result = false; 205 292 } 206 293 207 294 return result; 208 295 } 296 297 private static void incMap(Map<String, Integer> map, String key) { 298 map.putIfAbsent(key, 0); 299 map.put(key, map.get(key)+1); 300 } 209 301 } -
trunk/src/org/openstreetmap/josm/data/projection/CustomProjection.java
r13182 r13598 296 296 } 297 297 s = parameters.get(Param.bounds.key); 298 if (s != null) { 299 this.bounds = parseBounds(s); 300 } 298 this.bounds = s != null ? parseBounds(s) : null; 301 299 s = parameters.get(Param.wmssrs.key); 302 300 if (s != null) { … … 590 588 projParams.gamma = parseAngle(s, Param.gamma.key); 591 589 } 590 s = parameters.get(Param.lon_0.key); 591 if (s != null) { 592 projParams.lon0 = parseAngle(s, Param.lon_0.key); 593 } 592 594 s = parameters.get(Param.lon_1.key); 593 595 if (s != null) { -
trunk/src/org/openstreetmap/josm/data/projection/Projections.java
r13582 r13598 25 25 import org.openstreetmap.josm.data.projection.datum.WGS84Datum; 26 26 import org.openstreetmap.josm.data.projection.proj.AlbersEqualArea; 27 import org.openstreetmap.josm.data.projection.proj.AzimuthalEquidistant; 27 28 import org.openstreetmap.josm.data.projection.proj.CassiniSoldner; 28 29 import org.openstreetmap.josm.data.projection.proj.ClassProjFactory; 29 30 import org.openstreetmap.josm.data.projection.proj.DoubleStereographic; 31 import org.openstreetmap.josm.data.projection.proj.EquidistantCylindrical; 30 32 import org.openstreetmap.josm.data.projection.proj.LambertAzimuthalEqualArea; 31 33 import org.openstreetmap.josm.data.projection.proj.LambertConformalConic; … … 55 57 */ 56 58 public static class ProjectionDefinition { 59 /** 60 * EPSG code 61 */ 57 62 public final String code; 63 /** 64 * Projection name 65 */ 58 66 public final String name; 67 /** 68 * projection definition (EPSG format) 69 */ 59 70 public final String definition; 60 71 … … 89 100 static { 90 101 registerBaseProjection("aea", AlbersEqualArea.class, "core"); 102 registerBaseProjection("aeqd", AzimuthalEquidistant.class, "core"); 91 103 registerBaseProjection("cass", CassiniSoldner.class, "core"); 104 registerBaseProjection("eqc", EquidistantCylindrical.class, "core"); 92 105 registerBaseProjection("laea", LambertAzimuthalEqualArea.class, "core"); 93 106 registerBaseProjection("lcc", LambertConformalConic.class, "core"); … … 199 212 } 200 213 214 /** 215 * Plugins can register additional base projections. 216 * 217 * @param id The "official" PROJ.4 id. In case the projection is not supported 218 * by PROJ.4, use some prefix, e.g. josm:myproj or gdal:otherproj. 219 * @param projClass The base projection class. 220 * @param origin Multiple plugins may implement the same base projection. 221 * Provide plugin name or similar string, so it be differentiated. 222 */ 201 223 public static void registerBaseProjection(String id, Class<? extends Proj> projClass, String origin) { 202 224 registerBaseProjection(id, new ClassProjFactory(projClass), origin); … … 293 315 List<ProjectionDefinition> result = new ArrayList<>(); 294 316 Pattern epsgPattern = Pattern.compile("<(\\d+)>(.*)<>"); 295 String line, lastline = ""; 317 StringBuilder sb = new StringBuilder(); 318 String line; 296 319 while ((line = r.readLine()) != null) { 297 320 line = line.trim(); 298 if (!line.startsWith("#") && !line.isEmpty()) { 299 if (!lastline.startsWith("#")) throw new AssertionError("EPSG file seems corrupted"); 300 String name = lastline.substring(1).trim(); 301 Matcher m = epsgPattern.matcher(line); 302 if (m.matches()) { 303 String code = "EPSG:" + m.group(1); 304 String definition = m.group(2).trim(); 305 result.add(new ProjectionDefinition(code, name, definition)); 306 } else { 307 Logging.warn("Failed to parse line from the EPSG projection definition: "+line); 321 if (!line.isEmpty()) { 322 if (!line.startsWith("#")) { 323 Matcher m = epsgPattern.matcher(line); 324 if (m.matches()) { 325 String code = "EPSG:" + m.group(1); 326 String definition = m.group(2).trim(); 327 result.add(new ProjectionDefinition(code, sb.toString(), definition)); 328 } else { 329 Logging.warn("Failed to parse line from the EPSG projection definition: "+line); 330 } 331 sb.setLength(0); 332 } else if (!line.startsWith("# area: ")) { 333 if (sb.length() == 0) { 334 sb.append(line.substring(1).trim()); 335 } else { 336 sb.append('(').append(line.substring(1).trim()).append(')'); 337 } 308 338 } 309 339 } 310 lastline = line; 311 } 340 } 341 if (result.isEmpty()) 342 throw new AssertionError("EPSG file seems corrupted"); 312 343 return result; 313 344 } -
trunk/src/org/openstreetmap/josm/data/projection/proj/AbstractProj.java
r10748 r13598 155 155 } 156 156 157 /** 158 * Tolerant asin that will just return the limits of its output range if the input is out of range 159 * @param v the value whose arc sine is to be returned. 160 * @return the arc sine of the argument. 161 */ 162 protected final double aasin(double v) { 163 double av = Math.abs(v); 164 if (av >= 1.) { 165 return (v < 0. ? -Math.PI / 2 : Math.PI / 2); 166 } 167 return Math.asin(v); 168 } 169 157 170 // Iteratively solve equation (7-9) from Snyder. 158 171 final double cphi2(final double ts) { -
trunk/src/org/openstreetmap/josm/data/projection/proj/ProjParameters.java
r9565 r13598 2 2 package org.openstreetmap.josm.data.projection.proj; 3 3 4 import org.openstreetmap.josm.data.projection.CustomProjection.Param; 4 5 import org.openstreetmap.josm.data.projection.Ellipsoid; 5 6 6 7 /** 7 8 * Parameters to initialize a Proj object. 9 * @since 5066 8 10 */ 9 11 public class ProjParameters { 10 12 13 /** {@code +ellps} */ 11 14 public Ellipsoid ellps; 12 15 16 /** {@link Param#lat_0} */ 13 17 public Double lat0; 18 /** {@link Param#lat_1} */ 14 19 public Double lat1; 20 /** {@link Param#lat_2} */ 15 21 public Double lat2; 16 22 17 23 // Polar Stereographic and Mercator 24 /** {@link Param#lat_ts} */ 18 25 public Double lat_ts; 19 26 27 // Azimuthal Equidistant 28 /** {@link Param#lon_0} */ 29 public Double lon0; 30 20 31 // Oblique Mercator 32 /** {@link Param#lonc} */ 21 33 public Double lonc; 34 /** {@link Param#alpha} */ 22 35 public Double alpha; 36 /** {@link Param#gamma} */ 23 37 public Double gamma; 38 /** {@link Param#no_off} */ 24 39 public Boolean no_off; 40 /** {@link Param#lon_1} */ 25 41 public Double lon1; 42 /** {@link Param#lon_2} */ 26 43 public Double lon2; 27 44 } -
trunk/test/unit/org/openstreetmap/josm/data/projection/ProjectionRefTest.java
r12795 r13598 79 79 static Random rand = new SecureRandom(); 80 80 81 static boolean debug; 82 81 83 /** 82 84 * Setup test. … … 92 94 */ 93 95 public static void main(String[] args) throws IOException { 96 debug = args.length > 0 && "debug".equals(args[0]); 94 97 Collection<RefEntry> refs = readData(); 95 98 refs = updateData(refs); … … 236 239 pb.environment().put("PROJ_LIB", new File(PROJ_LIB_DIR).getAbsolutePath()); 237 240 238 String output; 241 String output = ""; 239 242 try { 240 243 Process process = pb.start(); 241 244 OutputStream stdin = process.getOutputStream(); 242 245 InputStream stdout = process.getInputStream(); 246 InputStream stderr = process.getErrorStream(); 243 247 try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(stdin, StandardCharsets.UTF_8))) { 244 writer.write(String.format("%.9f %.9f%n", ll.lon(), ll.lat())); 248 String s = String.format("%.9f %.9f%n", ll.lon(), ll.lat()); 249 if (debug) { 250 System.out.println("\n" + String.join(" ", args) + "\n" + s); 251 } 252 writer.write(s); 245 253 } 246 254 try (BufferedReader reader = new BufferedReader(new InputStreamReader(stdout, StandardCharsets.UTF_8))) { 247 output = reader.readLine(); 255 String line; 256 while (null != (line = reader.readLine())) { 257 if (debug) { 258 System.out.println("> " + line); 259 } 260 output = line; 261 } 262 } 263 try (BufferedReader reader = new BufferedReader(new InputStreamReader(stderr, StandardCharsets.UTF_8))) { 264 String line; 265 while (null != (line = reader.readLine())) { 266 System.err.println("! " + line); 267 } 248 268 } 249 269 } catch (IOException e) { -
trunk/test/unit/org/openstreetmap/josm/data/projection/ProjectionTest.java
r11324 r13598 24 24 String text; 25 25 26 /** 27 * Tests that projections are numerically stable in their definition bounds (round trip error < 1e-5) 28 */ 26 29 @Test 27 30 public void testProjections() { … … 55 58 testProjection(Projections.getProjectionByCode("EPSG:"+Integer.toString(3942+i))); // Lambert CC9 Zones France 56 59 } 60 61 for (int i = 0; i <= 17; ++i) { 62 testProjection(Projections.getProjectionByCode("EPSG:"+Integer.toString(102421+i))); // WGS_1984_ARC_System Zones 63 } 64 65 testProjection(Projections.getProjectionByCode("EPSG:102016")); // North Pole 66 testProjection(Projections.getProjectionByCode("EPSG:102019")); // South Pole 57 67 58 68 if (error) { … … 104 114 Collection<String> projIds; 105 115 116 /** 117 * Tests that projections are numerically stable in their definition bounds (round trip error < epsilon) 118 */ 106 119 @Test 107 120 public void testProjs() { … … 127 140 testProj("merc", 1e-5, ""); 128 141 testProj("sinu", 1e-4, ""); 142 testProj("aeqd", 1e-5, "+lon_0=0dE +lat_0=90dN"); 143 testProj("aeqd", 1e-5, "+lon_0=0dE +lat_0=90dS"); 144 testProj("eqc", 1e-5, ""); 129 145 130 146 if (error2) {
Note:
See TracChangeset
for help on using the changeset viewer.