Changeset 15033 in josm for trunk/scripts
- Timestamp:
- 2019-05-02T03:19:26+02:00 (6 years ago)
- File:
-
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
trunk/scripts/SyncEditorLayerIndex.java
r15001 r15033 1 1 // License: GPL. For details, see LICENSE file. 2 import static org.apache.commons.lang3.StringUtils.isBlank; 3 import static org.apache.commons.lang3.StringUtils.isNotBlank; 4 5 import java.io.BufferedReader; 6 import java.io.FileInputStream; 7 import java.io.FileNotFoundException; 8 import java.io.FileOutputStream; 9 import java.io.IOException; 10 import java.io.InputStreamReader; 11 import java.io.OutputStreamWriter; 12 import java.io.UnsupportedEncodingException; 13 import java.lang.reflect.Field; 14 import java.text.DecimalFormat; 15 import java.text.ParseException; 16 import java.text.SimpleDateFormat; 17 import java.util.ArrayList; 18 import java.util.Arrays; 19 import java.util.Calendar; 20 import java.util.Collection; 21 import java.util.Collections; 22 import java.util.Date; 23 import java.util.HashMap; 24 import java.util.LinkedList; 25 import java.util.List; 26 import java.util.Locale; 27 import java.util.Map; 28 import java.util.Map.Entry; 29 import java.util.Objects; 30 import java.util.regex.Matcher; 31 import java.util.regex.Pattern; 32 import java.util.stream.Collectors; 33 34 import javax.json.Json; 35 import javax.json.JsonArray; 36 import javax.json.JsonNumber; 37 import javax.json.JsonObject; 38 import javax.json.JsonReader; 39 import javax.json.JsonString; 40 import javax.json.JsonValue; 41 42 import org.openstreetmap.gui.jmapviewer.Coordinate; 43 import org.openstreetmap.josm.data.Preferences; 44 import org.openstreetmap.josm.data.imagery.ImageryInfo; 45 import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryBounds; 46 import org.openstreetmap.josm.data.imagery.Shape; 47 import org.openstreetmap.josm.data.preferences.JosmBaseDirectories; 48 import org.openstreetmap.josm.data.projection.Projections; 49 import org.openstreetmap.josm.data.validation.routines.DomainValidator; 50 import org.openstreetmap.josm.io.imagery.ImageryReader; 51 import org.openstreetmap.josm.spi.preferences.Config; 52 import org.openstreetmap.josm.tools.OptionParser; 53 import org.openstreetmap.josm.tools.OptionParser.OptionCount; 54 import org.openstreetmap.josm.tools.ReflectionUtils; 55 import org.xml.sax.SAXException; 56 2 57 /** 3 58 * Compare and analyse the differences of the editor layer index and the JOSM imagery list. … … 13 68 * Main JOSM binary needs to be in classpath, e.g. 14 69 * 15 * $ groovy -cp ../dist/josm-custom.jar SyncEditorLayerIndex.groovy70 * $ java -cp ../dist/josm-custom.jar SyncEditorLayerIndex 16 71 * 17 72 * Add option "-h" to show the available command line flags. 18 73 */ 19 import java.text.DecimalFormat 20 21 import javax.json.Json 22 import javax.json.JsonArray 23 import javax.json.JsonObject 24 import javax.json.JsonReader 25 import javax.json.JsonValue 26 27 import org.openstreetmap.josm.data.Preferences 28 import org.openstreetmap.josm.data.imagery.ImageryInfo 29 import org.openstreetmap.josm.data.imagery.Shape 30 import org.openstreetmap.josm.data.preferences.JosmBaseDirectories 31 import org.openstreetmap.josm.data.projection.Projections 32 import org.openstreetmap.josm.data.validation.routines.DomainValidator 33 import org.openstreetmap.josm.io.imagery.ImageryReader 34 import org.openstreetmap.josm.spi.preferences.Config 35 36 class SyncEditorLayerIndex { 37 38 List<ImageryInfo> josmEntries 39 JsonArray eliEntries 40 41 def eliUrls = new HashMap<String, JsonObject>() 42 def josmUrls = new HashMap<String, ImageryInfo>() 43 def josmMirrors = new HashMap<String, ImageryInfo>() 44 static def oldproj = new HashMap<String, String>() 45 static def ignoreproj = new LinkedList<String>() 46 47 static String eliInputFile = 'imagery_eli.geojson' 48 static String josmInputFile = 'imagery_josm.imagery.xml' 49 static String ignoreInputFile = 'imagery_josm.ignores.txt' 50 static FileOutputStream outputFile = null 51 static OutputStreamWriter outputStream = null 52 def skip = [:] 53 54 static def options 74 public class SyncEditorLayerIndex { 75 76 private List<ImageryInfo> josmEntries; 77 private JsonArray eliEntries; 78 79 private Map<String, JsonObject> eliUrls = new HashMap<>(); 80 private Map<String, ImageryInfo> josmUrls = new HashMap<>(); 81 private Map<String, ImageryInfo> josmMirrors = new HashMap<>(); 82 private static Map<String, String> oldproj = new HashMap<>(); 83 private static List<String> ignoreproj = new LinkedList<>(); 84 85 private static String eliInputFile = "imagery_eli.geojson"; 86 private static String josmInputFile = "imagery_josm.imagery.xml"; 87 private static String ignoreInputFile = "imagery_josm.ignores.txt"; 88 private static FileOutputStream outputFile = null; 89 private static OutputStreamWriter outputStream = null; 90 private static String optionOutput; 91 private static boolean optionShorten; 92 private static boolean optionNoSkip; 93 private static boolean optionXhtmlBody; 94 private static boolean optionXhtml; 95 private static String optionEliXml; 96 private static String optionJosmXml; 97 private static String optionEncoding; 98 private static boolean optionNoEli; 99 private Map<String, String> skip = new HashMap<>(); 55 100 56 101 /** 57 102 * Main method. 103 * @param args program arguments 104 * @throws IOException if any I/O error occurs 105 * @throws ReflectiveOperationException if any reflective operation error occurs 106 * @throws SAXException if any SAX error occurs 58 107 */ 59 static main(def args) { 60 Locale.setDefault(Locale.ROOT) 61 parse_command_line_arguments(args) 62 def pref = new Preferences(JosmBaseDirectories.getInstance()) 63 Config.setPreferencesInstance(pref) 64 pref.init(false) 65 def script = new SyncEditorLayerIndex() 66 script.setupProj() 67 script.loadSkip() 68 script.start() 69 script.loadJosmEntries() 70 if(options.josmxml) { 71 def file = new FileOutputStream(options.josmxml) 72 def stream = new OutputStreamWriter(file, "UTF-8") 73 script.printentries(script.josmEntries, stream) 74 stream.close() 75 file.close() 76 } 77 script.loadELIEntries() 78 if(options.elixml) { 79 def file = new FileOutputStream(options.elixml) 80 def stream = new OutputStreamWriter(file, "UTF-8") 81 script.printentries(script.eliEntries, stream) 82 stream.close() 83 file.close() 84 } 85 script.checkInOneButNotTheOther() 86 script.checkCommonEntries() 87 script.end() 88 if(outputStream != null) { 89 outputStream.close() 90 } 91 if(outputFile != null) { 92 outputFile.close() 93 } 108 public static void main(String[] args) throws IOException, SAXException, ReflectiveOperationException { 109 Locale.setDefault(Locale.ROOT); 110 parse_command_line_arguments(args); 111 Preferences pref = new Preferences(JosmBaseDirectories.getInstance()); 112 Config.setPreferencesInstance(pref); 113 pref.init(false); 114 SyncEditorLayerIndex script = new SyncEditorLayerIndex(); 115 script.setupProj(); 116 script.loadSkip(); 117 script.start(); 118 script.loadJosmEntries(); 119 if (optionJosmXml != null) { 120 FileOutputStream file = new FileOutputStream(optionJosmXml); 121 OutputStreamWriter stream = new OutputStreamWriter(file, "UTF-8"); 122 script.printentries(script.josmEntries, stream); 123 stream.close(); 124 file.close(); 125 } 126 script.loadELIEntries(); 127 if (optionEliXml != null) { 128 FileOutputStream file = new FileOutputStream(optionEliXml); 129 OutputStreamWriter stream = new OutputStreamWriter(file, "UTF-8"); 130 script.printentries(script.eliEntries, stream); 131 stream.close(); 132 file.close(); 133 } 134 script.checkInOneButNotTheOther(); 135 script.checkCommonEntries(); 136 script.end(); 137 if (outputStream != null) { 138 outputStream.close(); 139 } 140 if (outputFile != null) { 141 outputFile.close(); 142 } 143 } 144 145 /** 146 * Displays help on the console 147 */ 148 private static void showHelp() { 149 System.out.println(getHelp()); 150 System.exit(0); 151 } 152 153 static String getHelp() { 154 return "usage: java -cp build SyncEditorLayerIndex\n" + 155 "-c,--encoding <encoding> output encoding (defaults to UTF-8 or cp850 on Windows)\n" + 156 "-e,--eli_input <eli_input> Input file for the editor layer index (geojson). Default is imagery_eli.geojson (current directory).\n" + 157 "-h,--help show this help\n" + 158 "-i,--ignore_input <ignore_input> Input file for the ignore list. Default is imagery_josm.ignores.txt (current directory).\n" + 159 "-j,--josm_input <josm_input> Input file for the JOSM imagery list (xml). Default is imagery_josm.imagery.xml (current directory).\n" + 160 "-m,--noeli don't show output for ELI problems\n" + 161 "-n,--noskip don't skip known entries\n" + 162 "-o,--output <output> Output file, - prints to stdout (default: -)\n" + 163 "-p,--elixml <elixml> ELI entries for use in JOSM as XML file (incomplete)\n" + 164 "-q,--josmxml <josmxml> JOSM entries reoutput as XML file (incomplete)\n" + 165 "-s,--shorten shorten the output, so it is easier to read in a console window\n" + 166 "-x,--xhtmlbody create XHTML body for display in a web page\n" + 167 "-X,--xhtml create XHTML for display in a web page\n"; 94 168 } 95 169 96 170 /** 97 171 * Parse command line arguments. 172 * @param args program arguments 173 * @throws FileNotFoundException if a file can't be found 174 * @throws UnsupportedEncodingException if the given encoding can't be found 98 175 */ 99 static void parse_command_line_arguments( args){100 def cli = new CliBuilder(width: 160)101 cli.o(longOpt:'output', args:1, argName: "output", "Output file, - prints to stdout (default: -)")102 cli.e(longOpt:'eli_input', args:1, argName:"eli_input", "Input file for the editor layer index (geojson). Default is $eliInputFile (current directory).")103 cli.j(longOpt:'josm_input', args:1, argName:"josm_input", "Input file for the JOSM imagery list (xml). Default is $josmInputFile (current directory).")104 cli.i(longOpt:'ignore_input', args:1, argName:"ignore_input", "Input file for the ignore list. Default is $ignoreInputFile (current directory).")105 cli.s(longOpt:'shorten', "shorten the output, so it is easier to read in a console window")106 cli.n(longOpt:'noskip', argName:"noskip", "don't skip known entries")107 cli.x(longOpt:'xhtmlbody', argName:"xhtmlbody", "create XHTML body for display in a web page")108 cli.X(longOpt:'xhtml', argName:"xhtml", "create XHTML for display in a web page")109 cli.p(longOpt:'elixml', args:1, argName:"elixml", "ELI entries for use in JOSM as XML file (incomplete)")110 cli.q(longOpt:'josmxml', args:1, argName:"josmxml", "JOSM entries reoutput as XML file (incomplete)")111 cli.m(longOpt:'noeli', argName:"noeli", "don't show output for ELI problems")112 cli.c(longOpt:'encoding', args:1, argName:"encoding", "output encoding (defaults to UTF-8 or cp850 on Windows)")113 cli.h(longOpt:'help', "show this help")114 options = cli.parse(args)115 116 if (options.h) {117 cli.usage()118 System.exit(0)119 }120 if (options.eli_input) {121 eliInputFile = options.eli_input122 }123 if (options.josm_input) {124 josmInputFile = options.josm_input125 }126 if (options.ignore_input) {127 ignoreInputFile = options.ignore_input128 } 129 if (option s.output && options.output != "-") {130 outputFile = new FileOutputStream(option s.output)131 outputStream = new OutputStreamWriter(outputFile, option s.encoding ? options.encoding : "UTF-8")132 } else if (option s.encoding) {133 outputStream = new OutputStreamWriter(System.out, option s.encoding)176 static void parse_command_line_arguments(String[] args) throws FileNotFoundException, UnsupportedEncodingException { 177 new OptionParser("JOSM/ELI synchronization script") 178 .addFlagParameter("help", SyncEditorLayerIndex::showHelp) 179 .addShortAlias("help", "h") 180 .addArgumentParameter("output", OptionCount.OPTIONAL, x -> optionOutput = x) 181 .addShortAlias("output", "o") 182 .addArgumentParameter("eli_input", OptionCount.OPTIONAL, x -> eliInputFile = x) 183 .addShortAlias("eli_input", "e") 184 .addArgumentParameter("josm_input", OptionCount.OPTIONAL, x -> josmInputFile = x) 185 .addShortAlias("josm_input", "j") 186 .addArgumentParameter("ignore_input", OptionCount.OPTIONAL, x -> ignoreInputFile = x) 187 .addShortAlias("ignore_input", "i") 188 .addFlagParameter("shorten", () -> optionShorten = true) 189 .addShortAlias("shorten", "s") 190 .addFlagParameter("noskip", () -> optionNoSkip = true) 191 .addShortAlias("noskip", "n") 192 .addFlagParameter("xhtmlbody", () -> optionXhtmlBody = true) 193 .addShortAlias("xhtmlbody", "x") 194 .addFlagParameter("xhtml", () -> optionXhtml = true) 195 .addShortAlias("xhtml", "X") 196 .addArgumentParameter("elixml", OptionCount.OPTIONAL, x -> optionEliXml = x) 197 .addShortAlias("elixml", "p") 198 .addArgumentParameter("josmxml", OptionCount.OPTIONAL, x -> optionJosmXml = x) 199 .addShortAlias("josmxml", "q") 200 .addFlagParameter("noeli", () -> optionNoEli = true) 201 .addShortAlias("noeli", "m") 202 .addArgumentParameter("encoding", OptionCount.OPTIONAL, x -> optionEncoding = x) 203 .addShortAlias("encoding", "c") 204 .parseOptionsOrExit(Arrays.asList(args)); 205 206 if (optionOutput != null && optionOutput != "-") { 207 outputFile = new FileOutputStream(optionOutput); 208 outputStream = new OutputStreamWriter(outputFile, optionEncoding != null ? optionEncoding : "UTF-8"); 209 } else if (optionEncoding != null) { 210 outputStream = new OutputStreamWriter(System.out, optionEncoding); 134 211 } 135 212 } 136 213 137 214 void setupProj() { 138 oldproj.put("EPSG:3359", "EPSG:3404") 139 oldproj.put("EPSG:3785", "EPSG:3857") 140 oldproj.put("EPSG:31297", "EPGS:31287") 141 oldproj.put("EPSG:31464", "EPSG:31468") 142 oldproj.put("EPSG:54004", "EPSG:3857") 143 oldproj.put("EPSG:102100", "EPSG:3857") 144 oldproj.put("EPSG:102113", "EPSG:3857") 145 oldproj.put("EPSG:900913", "EPGS:3857") 146 ignoreproj.add("EPSG:4267") 147 ignoreproj.add("EPSG:5221") 148 ignoreproj.add("EPSG:5514") 149 ignoreproj.add("EPSG:32019") 150 ignoreproj.add("EPSG:102066") 151 ignoreproj.add("EPSG:102067") 152 ignoreproj.add("EPSG:102685") 153 ignoreproj.add("EPSG:102711") 154 } 155 156 void loadSkip() { 157 def fr = new InputStreamReader(new FileInputStream(ignoreInputFile), "UTF-8") 158 def line 159 160 while((line = fr.readLine()) != null) { 161 def res = (line =~ /^\|\| *(ELI|Ignore) *\|\| *\{\{\{(.+)\}\}\} *\|\|/) 162 if(res.count) 163 { 164 if(res[0][1].equals("Ignore")) { 165 skip[res[0][2]] = "green" 166 } else { 167 skip[res[0][2]] = "darkgoldenrod" 168 } 169 } 170 } 171 } 172 173 void myprintlnfinal(String s) { 174 if(outputStream != null) { 175 outputStream.write(s+System.getProperty("line.separator")) 215 oldproj.put("EPSG:3359", "EPSG:3404"); 216 oldproj.put("EPSG:3785", "EPSG:3857"); 217 oldproj.put("EPSG:31297", "EPGS:31287"); 218 oldproj.put("EPSG:31464", "EPSG:31468"); 219 oldproj.put("EPSG:54004", "EPSG:3857"); 220 oldproj.put("EPSG:102100", "EPSG:3857"); 221 oldproj.put("EPSG:102113", "EPSG:3857"); 222 oldproj.put("EPSG:900913", "EPGS:3857"); 223 ignoreproj.add("EPSG:4267"); 224 ignoreproj.add("EPSG:5221"); 225 ignoreproj.add("EPSG:5514"); 226 ignoreproj.add("EPSG:32019"); 227 ignoreproj.add("EPSG:102066"); 228 ignoreproj.add("EPSG:102067"); 229 ignoreproj.add("EPSG:102685"); 230 ignoreproj.add("EPSG:102711"); 231 } 232 233 void loadSkip() throws IOException { 234 final Pattern pattern = Pattern.compile("^\\|\\| *(ELI|Ignore) *\\|\\| *\\{\\{\\{(.+)\\}\\}\\} *\\|\\|"); 235 try (BufferedReader fr = new BufferedReader(new InputStreamReader(new FileInputStream(ignoreInputFile), "UTF-8"))) { 236 String line; 237 238 while ((line = fr.readLine()) != null) { 239 Matcher res = pattern.matcher(line); 240 if (res.matches()) { 241 if ("Ignore".equals(res.group(1))) { 242 skip.put(res.group(2), "green"); 243 } else { 244 skip.put(res.group(2), "darkgoldenrod"); 245 } 246 } 247 } 248 } 249 } 250 251 void myprintlnfinal(String s) throws IOException { 252 if (outputStream != null) { 253 outputStream.write(s + System.getProperty("line.separator")); 176 254 } else { 177 println s 178 } 179 } 180 181 void myprintln(String s) { 182 if(skip.containsKey(s)) { 183 String color = skip.get(s) 184 skip.remove(s) 185 if(options.xhtmlbody || options.xhtml) { 186 s = "<pre style=\"margin:3px;color:"+color+"\">"+s.replaceAll("&","&").replaceAll("<","<").replaceAll(">",">")+"</pre>" 187 } 188 if (!options.noskip) { 189 return 190 } 191 } else if(options.xhtmlbody || options.xhtml) { 192 String color = s.startsWith("***") ? "black" : ((s.startsWith("+ ") || s.startsWith("+++ ELI")) ? "blue" : 193 (s.startsWith("#") ? "indigo" : (s.startsWith("!") ? "orange" : "red"))) 194 s = "<pre style=\"margin:3px;color:"+color+"\">"+s.replaceAll("&","&").replaceAll("<","<").replaceAll(">",">")+"</pre>" 195 } 196 if ((s.startsWith("+ ") || s.startsWith("+++ ELI") || s.startsWith("#")) && options.noeli) { 197 return 198 } 199 myprintlnfinal(s) 200 } 201 202 void start() { 203 if (options.xhtml) { 204 myprintlnfinal "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n" 205 myprintlnfinal "<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"/><title>JOSM - ELI differences</title></head><body>\n" 206 } 207 } 208 209 void end() { 210 for (def s: skip.keySet()) { 211 myprintln "+++ Obsolete skip entry: " + s 212 } 213 if (options.xhtml) { 214 myprintlnfinal "</body></html>\n" 215 } 216 } 217 218 void loadELIEntries() { 219 def fr = new InputStreamReader(new FileInputStream(eliInputFile), "UTF-8") 220 JsonReader jr = Json.createReader(fr) 221 eliEntries = jr.readObject().get("features") 222 jr.close() 223 224 for (def e : eliEntries) { 225 def url = getUrlStripped(e) 255 System.out.println(s); 256 } 257 } 258 259 void myprintln(String s) throws IOException { 260 if (skip.containsKey(s)) { 261 String color = skip.get(s); 262 skip.remove(s); 263 if (optionXhtmlBody || optionXhtml) { 264 s = "<pre style=\"margin:3px;color:"+color+"\">"+s.replaceAll("&","&").replaceAll("<","<").replaceAll(">",">")+"</pre>"; 265 } 266 if (!optionNoSkip) { 267 return; 268 } 269 } else if(optionXhtmlBody || optionXhtml) { 270 String color = 271 s.startsWith("***") ? "black" : 272 ((s.startsWith("+ ") || s.startsWith("+++ ELI")) ? "blue" : 273 (s.startsWith("#") ? "indigo" : 274 (s.startsWith("!") ? "orange" : "red"))); 275 s = "<pre style=\"margin:3px;color:"+color+"\">"+s.replaceAll("&","&").replaceAll("<","<").replaceAll(">",">")+"</pre>"; 276 } 277 if ((s.startsWith("+ ") || s.startsWith("+++ ELI") || s.startsWith("#")) && optionNoEli) { 278 return; 279 } 280 myprintlnfinal(s); 281 } 282 283 void start() throws IOException { 284 if (optionXhtml) { 285 myprintlnfinal("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"); 286 myprintlnfinal("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"/><title>JOSM - ELI differences</title></head><body>\n"); 287 } 288 } 289 290 void end() throws IOException { 291 for (String s : skip.keySet()) { 292 myprintln("+++ Obsolete skip entry: " + s); 293 } 294 if (optionXhtml) { 295 myprintlnfinal("</body></html>\n"); 296 } 297 } 298 299 void loadELIEntries() throws IOException { 300 try (JsonReader jr = Json.createReader(new InputStreamReader(new FileInputStream(eliInputFile), "UTF-8"))) { 301 eliEntries = jr.readObject().getJsonArray("features"); 302 } 303 304 for (JsonValue e : eliEntries) { 305 String url = getUrlStripped(e); 226 306 if (url.contains("{z}")) { 227 myprintln "+++ ELI-URL uses {z} instead of {zoom}: "+url228 url = url.replace("{z}","{zoom}") 307 myprintln("+++ ELI-URL uses {z} instead of {zoom}: "+url); 308 url = url.replace("{z}","{zoom}"); 229 309 } 230 310 if (eliUrls.containsKey(url)) { 231 myprintln "+++ ELI-URL is not unique: "+url311 myprintln("+++ ELI-URL is not unique: "+url); 232 312 } else { 233 eliUrls.put(url, e) 234 } 235 def s = e.get("properties").get("available_projections") 236 if (s) { 237 def old = new LinkedList<String>() 238 for (def p : s) { 239 def proj = p.getString() 240 if(oldproj.containsKey(proj) || ("CRS:84".equals(proj) && !(url =~ /(?i)version=1\.3/))) { 241 old.add(proj) 242 } 243 } 244 if (old) { 245 def str = String.join(", ", old) 246 myprintln "+ ELI Projections ${str} not useful: ${getDescription(e)}" 247 } 248 } 249 } 250 myprintln "*** Loaded ${eliEntries.size()} entries (ELI). ***" 251 } 252 String cdata(def s, boolean escape = false) { 253 if(escape) { 254 return s.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">") 255 } else if(s =~ /[<>&]/) 256 return "<![CDATA[$s]]>" 257 return s 258 } 259 260 String maininfo(def entry, String offset) { 261 String t = getType(entry) 262 String res = offset + "<type>$t</type>\n" 263 res += offset + "<url>${cdata(getUrl(entry))}</url>\n" 264 if(getMinZoom(entry) != null) 265 res += offset + "<min-zoom>${getMinZoom(entry)}</min-zoom>\n" 266 if(getMaxZoom(entry) != null) 267 res += offset + "<max-zoom>${getMaxZoom(entry)}</max-zoom>\n" 268 if (t == "wms") { 269 def p = getProjections(entry) 270 if (p) { 271 res += offset + "<projections>\n" 272 for (def c : p) 273 res += offset + " <code>$c</code>\n" 274 res += offset + "</projections>\n" 275 } 276 } 277 return res 278 } 279 280 void printentries(def entries, def stream) { 281 DecimalFormat df = new DecimalFormat("#.#######") 282 df.setRoundingMode(java.math.RoundingMode.CEILING) 283 stream.write "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n" 284 stream.write "<imagery xmlns=\"http://josm.openstreetmap.de/maps-1.0\">\n" 285 for (def e : entries) { 313 eliUrls.put(url, e.asJsonObject()); 314 } 315 JsonArray s = e.asJsonObject().get("properties").asJsonObject().getJsonArray("available_projections"); 316 if (s != null) { 317 String urlLc = url.toLowerCase(Locale.ENGLISH); 318 List<String> old = new LinkedList<>(); 319 for (JsonValue p : s) { 320 String proj = ((JsonString) p).getString(); 321 if (oldproj.containsKey(proj) || ("CRS:84".equals(proj) && !urlLc.contains("version=1.3"))) { 322 old.add(proj); 323 } 324 } 325 if (!old.isEmpty()) { 326 myprintln("+ ELI Projections "+String.join(", ", old)+" not useful: "+getDescription(e)); 327 } 328 } 329 } 330 myprintln("*** Loaded "+eliEntries.size()+" entries (ELI). ***"); 331 } 332 333 String cdata(String s) { 334 return cdata(s, false); 335 } 336 337 String cdata(String s, boolean escape) { 338 if (escape) { 339 return s.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">"); 340 } else if (s.matches("[<>&]")) 341 return "<![CDATA["+s+"]]>"; 342 return s; 343 } 344 345 String maininfo(Object entry, String offset) { 346 String t = getType(entry); 347 String res = offset + "<type>"+t+"</type>\n"; 348 res += offset + "<url>"+cdata(getUrl(entry))+"</url>\n"; 349 if (getMinZoom(entry) != null) 350 res += offset + "<min-zoom>"+getMinZoom(entry)+"</min-zoom>\n"; 351 if (getMaxZoom(entry) != null) 352 res += offset + "<max-zoom>"+getMaxZoom(entry)+"</max-zoom>\n"; 353 if ("wms".equals(t)) { 354 List<String> p = getProjections(entry); 355 if (p != null) { 356 res += offset + "<projections>\n"; 357 for (String c : p) 358 res += offset + " <code>"+c+"</code>\n"; 359 res += offset + "</projections>\n"; 360 } 361 } 362 return res; 363 } 364 365 void printentries(List<?> entries, OutputStreamWriter stream) throws IOException { 366 DecimalFormat df = new DecimalFormat("#.#######"); 367 df.setRoundingMode(java.math.RoundingMode.CEILING); 368 stream.write("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n"); 369 stream.write("<imagery xmlns=\"http://josm.openstreetmap.de/maps-1.0\">\n"); 370 for (Object e : entries) { 286 371 stream.write(" <entry" 287 372 + ("eli-best".equals(getQuality(e)) ? " eli-best=\"true\"" : "" ) 288 373 + (getOverlay(e) ? " overlay=\"true\"" : "" ) 289 + ">\n") 290 def t291 if ((t = getName(e)))292 stream.write " <name>${cdata(t, true)}</name>\n"293 if ((t = getId(e)))294 stream.write " <id>$t</id>\n"295 if ((t = getCategory(e)))296 stream.write " <category>$t</category>\n"297 if ((t = getDate(e)))298 stream.write " <date>$t</date>\n"299 if ((t = getCountryCode(e)))300 stream.write " <country-code>$t</country-code>\n"301 if ((getDefault(e)))302 stream.write " <default>true</default>\n"303 stream.write maininfo(e, " ")304 if ((t = getAttributionText(e)))305 stream.write " <attribution-text mandatory=\"true\">${cdata(t, true)}</attribution-text>\n"306 if ((t = getAttributionUrl(e)))307 stream.write " <attribution-url>${cdata(t)}</attribution-url>\n"308 if ((t = getLogoImage(e)))309 stream.write " <logo-image>${cdata(t, true)}</logo-image>\n"310 if ((t = getLogoUrl(e)))311 stream.write " <logo-url>${cdata(t)}</logo-url>\n"312 if ((t = getTermsOfUseText(e)))313 stream.write " <terms-of-use-text>${cdata(t, true)}</terms-of-use-text>\n"314 if ((t = getTermsOfUseUrl(e)))315 stream.write " <terms-of-use-url>${cdata(t)}</terms-of-use-url>\n"316 if ((t = getPermissionReferenceUrl(e)))317 stream.write " <permission-ref>${cdata(t)}</permission-ref>\n"318 if ((getValidGeoreference(e)))319 stream.write " <valid-georeference>true</valid-georeference>\n"320 if ((t = getIcon(e)))321 stream.write " <icon>${cdata(t)}</icon>\n"322 for ( def d : getDescriptions(e)) {323 stream.write " <description lang=\"${d.getKey()}\">${d.getValue()}</description>\n"324 } 325 for ( defm : getMirrors(e)) {326 stream.write " <mirror>\n"+maininfo(m, " ")+" </mirror>\n"327 } 328 d ef minlat = 1000329 d ef minlon = 1000330 d ef maxlat = -1000331 d ef maxlon = -1000332 def shapes = ""333 def sep = "\n "374 + ">\n"); 375 String t; 376 if (isNotBlank(t = getName(e))) 377 stream.write(" <name>"+cdata(t, true)+"</name>\n"); 378 if (isNotBlank(t = getId(e))) 379 stream.write(" <id>"+t+"</id>\n"); 380 if (isNotBlank(t = getCategory(e))) 381 stream.write(" <category>"+t+"</category>\n"); 382 if (isNotBlank(t = getDate(e))) 383 stream.write(" <date>"+t+"</date>\n"); 384 if (isNotBlank(t = getCountryCode(e))) 385 stream.write(" <country-code>"+t+"</country-code>\n"); 386 if ((getDefault(e))) 387 stream.write(" <default>true</default>\n"); 388 stream.write(maininfo(e, " ")); 389 if (isNotBlank(t = getAttributionText(e))) 390 stream.write(" <attribution-text mandatory=\"true\">"+cdata(t, true)+"</attribution-text>\n"); 391 if (isNotBlank(t = getAttributionUrl(e))) 392 stream.write(" <attribution-url>"+cdata(t)+"</attribution-url>\n"); 393 if (isNotBlank(t = getLogoImage(e))) 394 stream.write(" <logo-image>"+cdata(t, true)+"</logo-image>\n"); 395 if (isNotBlank(t = getLogoUrl(e))) 396 stream.write(" <logo-url>"+cdata(t)+"</logo-url>\n"); 397 if (isNotBlank(t = getTermsOfUseText(e))) 398 stream.write(" <terms-of-use-text>"+cdata(t, true)+"</terms-of-use-text>\n"); 399 if (isNotBlank(t = getTermsOfUseUrl(e))) 400 stream.write(" <terms-of-use-url>"+cdata(t)+"</terms-of-use-url>\n"); 401 if (isNotBlank(t = getPermissionReferenceUrl(e))) 402 stream.write(" <permission-ref>"+cdata(t)+"</permission-ref>\n"); 403 if ((getValidGeoreference(e))) 404 stream.write(" <valid-georeference>true</valid-georeference>\n"); 405 if (isNotBlank(t = getIcon(e))) 406 stream.write(" <icon>"+cdata(t)+"</icon>\n"); 407 for (Entry<String, String> d : getDescriptions(e).entrySet()) { 408 stream.write(" <description lang=\""+d.getKey()+"\">"+d.getValue()+"</description>\n"); 409 } 410 for (ImageryInfo m : getMirrors(e)) { 411 stream.write(" <mirror>\n"+maininfo(m, " ")+" </mirror>\n"); 412 } 413 double minlat = 1000; 414 double minlon = 1000; 415 double maxlat = -1000; 416 double maxlon = -1000; 417 String shapes = ""; 418 String sep = "\n "; 334 419 try { 335 for (defs: getShapes(e)) {336 shapes += " <shape>" 337 def i = 0338 for (defp: s.getPoints()) {339 d ef lat = p.getLat()340 d ef lon = p.getLon()341 if (lat > maxlat) maxlat = lat342 if (lon > maxlon) maxlon = lon343 if (lat < minlat) minlat = lat344 if (lon < minlon) minlon = lon345 if (!(i++%3)) {346 shapes += sep + " " 420 for (Shape s: getShapes(e)) { 421 shapes += " <shape>"; 422 int i = 0; 423 for (Coordinate p: s.getPoints()) { 424 double lat = p.getLat(); 425 double lon = p.getLon(); 426 if (lat > maxlat) maxlat = lat; 427 if (lon > maxlon) maxlon = lon; 428 if (lat < minlat) minlat = lat; 429 if (lon < minlon) minlon = lon; 430 if ((i++%3) == 0) { 431 shapes += sep + " "; 347 432 } 348 shapes += "<point lat=' ${df.format(lat)}' lon='${df.format(lon)}'/>"349 } 350 shapes += sep + "</shape>\n" 433 shapes += "<point lat='"+df.format(lat)+"' lon='"+df.format(lon)+"'/>"; 434 } 435 shapes += sep + "</shape>\n"; 351 436 } 352 437 } catch(IllegalArgumentException ignored) { 353 438 } 354 if(shapes) { 355 stream.write " <bounds min-lat='${df.format(minlat)}' min-lon='${df.format(minlon)}' max-lat='${df.format(maxlat)}' max-lon='${df.format(maxlon)}'>\n" 356 stream.write shapes + " </bounds>\n" 357 } 358 stream.write " </entry>\n" 359 } 360 stream.write "</imagery>\n" 361 stream.close() 362 } 363 364 void loadJosmEntries() { 365 def reader = new ImageryReader(josmInputFile) 366 josmEntries = reader.parse() 367 368 for (def e : josmEntries) { 369 if(!getUrl(e)) { 370 myprintln "+++ JOSM-Entry without URL: " + getDescription(e) 439 if (!shapes.isEmpty()) { 440 stream.write(" <bounds min-lat='"+df.format(minlat)+"' min-lon='"+df.format(minlon)+"' max-lat='"+df.format(maxlat)+"' max-lon='"+df.format(maxlon)+"'>\n"); 441 stream.write(shapes + " </bounds>\n"); 442 } 443 stream.write(" </entry>\n"); 444 } 445 stream.write("</imagery>\n"); 446 stream.close(); 447 } 448 449 void loadJosmEntries() throws IOException, SAXException, ReflectiveOperationException { 450 try (ImageryReader reader = new ImageryReader(josmInputFile)) { 451 josmEntries = reader.parse(); 452 } 453 454 for (ImageryInfo e : josmEntries) { 455 if (isBlank(getUrl(e))) { 456 myprintln("+++ JOSM-Entry without URL: " + getDescription(e)); 457 continue; 458 } 459 if (isBlank(getName(e))) { 460 myprintln("+++ JOSM-Entry without Name: " + getDescription(e)); 461 continue; 462 } 463 String url = getUrlStripped(e); 464 if (url.contains("{z}")) { 465 myprintln("+++ JOSM-URL uses {z} instead of {zoom}: "+url); 466 url = url.replace("{z}","{zoom}"); 467 } 468 if (josmUrls.containsKey(url)) { 469 myprintln("+++ JOSM-URL is not unique: "+url); 470 } else { 471 josmUrls.put(url, e); 472 } 473 for (ImageryInfo m : e.getMirrors()) { 474 url = getUrlStripped(m); 475 Field origNameField = ImageryInfo.class.getDeclaredField("origName"); 476 ReflectionUtils.setObjectsAccessible(origNameField); 477 origNameField.set(m, m.getOriginalName().replaceAll(" mirror server( \\d+)?","")); 478 if (josmUrls.containsKey(url)) { 479 myprintln("+++ JOSM-Mirror-URL is not unique: "+url); 480 } else { 481 josmUrls.put(url, m); 482 josmMirrors.put(url, m); 483 } 484 } 485 } 486 myprintln("*** Loaded "+josmEntries.size()+" entries (JOSM). ***"); 487 } 488 489 void checkInOneButNotTheOther() throws IOException { 490 List<String> le = new LinkedList<>(eliUrls.keySet()); 491 List<String> lj = new LinkedList<>(josmUrls.keySet()); 492 493 List<String> ke = new LinkedList<>(le); 494 for (String url : ke) { 495 if (lj.contains(url)) { 496 le.remove(url); 497 lj.remove(url); 498 } 499 } 500 501 if (!le.isEmpty() && !lj.isEmpty()) { 502 ke = new LinkedList<>(le); 503 for (String urle : ke) { 504 JsonObject e = eliUrls.get(urle); 505 String ide = getId(e); 506 String urlhttps = urle.replace("http:","https:"); 507 if (lj.contains(urlhttps)) { 508 myprintln("+ Missing https: "+getDescription(e)); 509 eliUrls.put(urlhttps, eliUrls.get(urle)); 510 eliUrls.remove(urle); 511 le.remove(urle); 512 lj.remove(urlhttps); 513 } else if (isNotBlank(ide)) { 514 List<String> kj = new LinkedList<>(lj); 515 for (String urlj : kj) { 516 ImageryInfo j = josmUrls.get(urlj); 517 String idj = getId(j); 518 519 if (ide.equals(idj) && Objects.equals(getType(j), getType(e))) { 520 myprintln("* URL for id "+idj+" differs ("+urle+"): "+getDescription(j)); 521 le.remove(urle); 522 lj.remove(urlj); 523 // replace key for this entry with JOSM URL 524 eliUrls.remove(urle); 525 eliUrls.put(urlj,e); 526 break; 527 } 528 } 529 } 530 } 531 } 532 533 myprintln("*** URLs found in ELI but not in JOSM ("+le.size()+"): ***"); 534 Collections.sort(le); 535 if (!le.isEmpty()) { 536 for (String l : le) { 537 myprintln("- " + getDescription(eliUrls.get(l))); 538 } 539 } 540 myprintln("*** URLs found in JOSM but not in ELI ("+lj.size()+"): ***"); 541 Collections.sort(lj); 542 if (!lj.isEmpty()) { 543 for (String l : lj) { 544 myprintln("+ " + getDescription(josmUrls.get(l))); 545 } 546 } 547 } 548 549 void checkCommonEntries() throws IOException { 550 myprintln("*** Same URL, but different name: ***"); 551 for (String url : eliUrls.keySet()) { 552 JsonObject e = eliUrls.get(url); 553 if (!josmUrls.containsKey(url)) continue; 554 ImageryInfo j = josmUrls.get(url); 555 String ename = getName(e).replace("'","\u2019"); 556 String jname = getName(j).replace("'","\u2019"); 557 if (!ename.equals(jname)) { 558 myprintln("* Name differs ('"+getName(e)+"' != '"+getName(j)+"'): "+getUrl(j)); 559 } 560 } 561 562 myprintln("*** Same URL, but different Id: ***"); 563 for (String url : eliUrls.keySet()) { 564 JsonObject e = eliUrls.get(url); 565 if (!josmUrls.containsKey(url)) continue; 566 ImageryInfo j = josmUrls.get(url); 567 String ename = getId(e); 568 String jname = getId(j); 569 if (!Objects.equals(ename, jname)) { 570 myprintln("# Id differs ('"+getId(e)+"' != '"+getId(j)+"'): "+getUrl(j)); 571 } 572 } 573 574 myprintln("*** Same URL, but different type: ***"); 575 for (String url : eliUrls.keySet()) { 576 JsonObject e = eliUrls.get(url); 577 if (!josmUrls.containsKey(url)) continue; 578 ImageryInfo j = josmUrls.get(url); 579 if (!Objects.equals(getType(e), getType(j))) { 580 myprintln("* Type differs ("+getType(e)+" != "+getType(j)+"): "+getName(j)+" - "+getUrl(j)); 581 } 582 } 583 584 myprintln("*** Same URL, but different zoom bounds: ***"); 585 for (String url : eliUrls.keySet()) { 586 JsonObject e = eliUrls.get(url); 587 if (!josmUrls.containsKey(url)) continue; 588 ImageryInfo j = josmUrls.get(url); 589 590 Integer eMinZoom = getMinZoom(e); 591 Integer jMinZoom = getMinZoom(j); 592 /* dont warn for entries copied from the base of the mirror */ 593 if (eMinZoom == null && "wms".equals(getType(j)) && j.getName().contains(" mirror")) 594 jMinZoom = null; 595 if (!Objects.equals(eMinZoom, jMinZoom) && !(Objects.equals(eMinZoom, 0) && jMinZoom == null)) { 596 myprintln("* Minzoom differs ("+eMinZoom+" != "+jMinZoom+"): "+getDescription(j)); 597 } 598 Integer eMaxZoom = getMaxZoom(e); 599 Integer jMaxZoom = getMaxZoom(j); 600 /* dont warn for entries copied from the base of the mirror */ 601 if (eMaxZoom == null && "wms".equals(getType(j)) && j.getName().contains(" mirror")) 602 jMaxZoom = null; 603 if (!Objects.equals(eMaxZoom, jMaxZoom)) { 604 myprintln("* Maxzoom differs ("+eMaxZoom+" != "+jMaxZoom+"): "+getDescription(j)); 605 } 606 } 607 608 myprintln("*** Same URL, but different country code: ***"); 609 for (String url : eliUrls.keySet()) { 610 JsonObject e = eliUrls.get(url); 611 if (!josmUrls.containsKey(url)) continue; 612 ImageryInfo j = josmUrls.get(url); 613 String cce = getCountryCode(e); 614 if ("ZZ".equals(cce)) { /* special ELI country code */ 615 cce = null; 616 } 617 if (cce != null && !cce.equals(getCountryCode(j))) { 618 myprintln("* Country code differs ("+getCountryCode(e)+" != "+getCountryCode(j)+"): "+getDescription(j)); 619 } 620 } 621 myprintln("*** Same URL, but different quality: ***"); 622 for (String url : eliUrls.keySet()) { 623 JsonObject e = eliUrls.get(url); 624 if (!josmUrls.containsKey(url)) { 625 String q = getQuality(e); 626 if ("eli-best".equals(q)) { 627 myprintln("- Quality best entry not in JOSM for "+getDescription(e)); 628 } 371 629 continue; 372 630 } 373 if(!getName(e)) { 374 myprintln "+++ JOSM-Entry without Name: " + getDescription(e) 375 continue; 376 } 377 def url = getUrlStripped(e) 378 if (url.contains("{z}")) { 379 myprintln "+++ JOSM-URL uses {z} instead of {zoom}: "+url 380 url = url.replace("{z}","{zoom}") 381 } 382 if (josmUrls.containsKey(url)) { 383 myprintln "+++ JOSM-URL is not unique: "+url 384 } else { 385 josmUrls.put(url, e) 386 } 387 for (def m : e.getMirrors()) { 388 url = getUrlStripped(m) 389 m.origName = m.getOriginalName().replaceAll(" mirror server( \\d+)?","") 390 if (josmUrls.containsKey(url)) { 391 myprintln "+++ JOSM-Mirror-URL is not unique: "+url 392 } else { 393 josmUrls.put(url, m) 394 josmMirrors.put(url, m) 395 } 396 } 397 } 398 myprintln "*** Loaded ${josmEntries.size()} entries (JOSM). ***" 399 } 400 401 void checkInOneButNotTheOther() { 402 def le = new LinkedList<String>(eliUrls.keySet()) 403 def lj = new LinkedList<String>(josmUrls.keySet()) 404 405 def ke = new LinkedList<String>(le) 406 for (def url : ke) { 407 if(lj.contains(url)) { 408 le.remove(url) 409 lj.remove(url) 410 } 411 } 412 413 if(le && lj) { 414 ke = new LinkedList<String>(le) 415 for (def urle : ke) { 416 def e = eliUrls.get(urle) 417 def ide = getId(e) 418 String urlhttps = urle.replace("http:","https:") 419 if(lj.contains(urlhttps)) 420 { 421 myprintln "+ Missing https: ${getDescription(e)}" 422 eliUrls.put(urlhttps, eliUrls.get(urle)) 423 eliUrls.remove(urle) 424 le.remove(urle) 425 lj.remove(urlhttps) 426 } else if(ide) { 427 def kj = new LinkedList<String>(lj) 428 for (def urlj : kj) { 429 def j = josmUrls.get(urlj) 430 def idj = getId(j) 431 432 if (ide.equals(idj) && getType(j) == getType(e)) { 433 myprintln "* URL for id ${idj} differs ($urle): ${getDescription(j)}" 434 le.remove(urle) 435 lj.remove(urlj) 436 /* replace key for this entry with JOSM URL */ 437 eliUrls.remove(urle) 438 eliUrls.put(urlj,e) 439 break 440 } 441 } 442 } 443 } 444 } 445 446 myprintln "*** URLs found in ELI but not in JOSM (${le.size()}): ***" 447 le.sort() 448 if (!le.isEmpty()) { 449 for (def l : le) { 450 myprintln "- " + getDescription(eliUrls.get(l)) 451 } 452 } 453 myprintln "*** URLs found in JOSM but not in ELI (${lj.size()}): ***" 454 lj.sort() 455 if (!lj.isEmpty()) { 456 for (def l : lj) { 457 myprintln "+ " + getDescription(josmUrls.get(l)) 458 } 459 } 460 } 461 462 void checkCommonEntries() { 463 myprintln "*** Same URL, but different name: ***" 464 for (def url : eliUrls.keySet()) { 465 def e = eliUrls.get(url) 466 if (!josmUrls.containsKey(url)) continue 467 def j = josmUrls.get(url) 468 def ename = getName(e).replace("'","\u2019") 469 def jname = getName(j).replace("'","\u2019") 470 if (!ename.equals(jname)) { 471 myprintln "* Name differs ('${getName(e)}' != '${getName(j)}'): ${getUrl(j)}" 472 } 473 } 474 475 myprintln "*** Same URL, but different Id: ***" 476 for (def url : eliUrls.keySet()) { 477 def e = eliUrls.get(url) 478 if (!josmUrls.containsKey(url)) continue 479 def j = josmUrls.get(url) 480 def ename = getId(e) 481 def jname = getId(j) 482 if (!ename.equals(jname)) { 483 myprintln "# Id differs ('${getId(e)}' != '${getId(j)}'): ${getUrl(j)}" 484 } 485 } 486 487 myprintln "*** Same URL, but different type: ***" 488 for (def url : eliUrls.keySet()) { 489 def e = eliUrls.get(url) 490 if (!josmUrls.containsKey(url)) continue 491 def j = josmUrls.get(url) 492 if (!getType(e).equals(getType(j))) { 493 myprintln "* Type differs (${getType(e)} != ${getType(j)}): ${getName(j)} - ${getUrl(j)}" 494 } 495 } 496 497 myprintln "*** Same URL, but different zoom bounds: ***" 498 for (def url : eliUrls.keySet()) { 499 def e = eliUrls.get(url) 500 if (!josmUrls.containsKey(url)) continue 501 def j = josmUrls.get(url) 502 503 Integer eMinZoom = getMinZoom(e) 504 Integer jMinZoom = getMinZoom(j) 505 /* dont warn for entries copied from the base of the mirror */ 506 if(eMinZoom == null && "wms".equals(getType(j)) && j.getName() =~ / mirror/) 507 jMinZoom = null; 508 if (eMinZoom != jMinZoom && !(eMinZoom == 0 && jMinZoom == null)) { 509 myprintln "* Minzoom differs (${eMinZoom} != ${jMinZoom}): ${getDescription(j)}" 510 } 511 Integer eMaxZoom = getMaxZoom(e) 512 Integer jMaxZoom = getMaxZoom(j) 513 /* dont warn for entries copied from the base of the mirror */ 514 if(eMaxZoom == null && "wms".equals(getType(j)) && j.getName() =~ / mirror/) 515 jMaxZoom = null; 516 if (eMaxZoom != jMaxZoom) { 517 myprintln "* Maxzoom differs (${eMaxZoom} != ${jMaxZoom}): ${getDescription(j)}" 518 } 519 } 520 521 myprintln "*** Same URL, but different country code: ***" 522 for (def url : eliUrls.keySet()) { 523 def e = eliUrls.get(url) 524 if (!josmUrls.containsKey(url)) continue 525 def j = josmUrls.get(url) 526 def cce = getCountryCode(e) 527 if ("ZZ".equals(cce)) { /* special ELI country code */ 528 cce = null 529 } 530 if (!cce.equals(getCountryCode(j))) { 531 myprintln "* Country code differs (${getCountryCode(e)} != ${getCountryCode(j)}): ${getDescription(j)}" 532 } 533 } 534 myprintln "*** Same URL, but different quality: ***" 535 for (def url : eliUrls.keySet()) { 536 def e = eliUrls.get(url) 537 if (!josmUrls.containsKey(url)) { 538 def q = getQuality(e) 539 if("eli-best".equals(q)) { 540 myprintln "- Quality best entry not in JOSM for ${getDescription(e)}" 541 } 542 continue 543 } 544 def j = josmUrls.get(url) 545 if (!getQuality(e).equals(getQuality(j))) { 546 myprintln "* Quality differs (${getQuality(e)} != ${getQuality(j)}): ${getDescription(j)}" 547 } 548 } 549 myprintln "*** Same URL, but different dates: ***" 550 for (def url : eliUrls.keySet()) { 551 def ed = getDate(eliUrls.get(url)) 552 if (!josmUrls.containsKey(url)) continue 553 def j = josmUrls.get(url) 554 def jd = getDate(j) 631 ImageryInfo j = josmUrls.get(url); 632 if (!Objects.equals(getQuality(e), getQuality(j))) { 633 myprintln("* Quality differs ("+getQuality(e)+" != "+getQuality(j)+"): "+getDescription(j)); 634 } 635 } 636 myprintln("*** Same URL, but different dates: ***"); 637 Pattern pattern = Pattern.compile("^(.*;)(\\d\\d\\d\\d)(-(\\d\\d)(-(\\d\\d))?)?$"); 638 for (String url : eliUrls.keySet()) { 639 String ed = getDate(eliUrls.get(url)); 640 if (!josmUrls.containsKey(url)) continue; 641 ImageryInfo j = josmUrls.get(url); 642 String jd = getDate(j); 555 643 // The forms 2015;- or -;2015 or 2015;2015 are handled equal to 2015 556 String ef = ed.replaceAll("\\A-;","").replaceAll(";-\\z","").replaceAll("\\A([0-9-]+);\\1\\z", "\$1")644 String ef = ed.replaceAll("\\A-;","").replaceAll(";-\\z","").replaceAll("\\A([0-9-]+);\\1\\z", "$1"); 557 645 // ELI has a strange and inconsistent used end_date definition, so we try again with subtraction by one 558 String ed2 = ed 559 def reg = (ed =~ /^(.*;)(\d\d\d\d)(-(\d\d)(-(\d\d))?)?$/) 560 if(reg != null && reg.count == 1) { 561 Calendar cal = Calendar.getInstance() 562 cal.set(reg[0][2] as Integer, reg[0][4] == null ? 0 : (reg[0][4] as Integer)-1, reg[0][6] == null ? 1 : reg[0][6] as Integer) 563 cal.add(Calendar.DAY_OF_MONTH, -1) 564 ed2 = reg[0][1] + cal.get(Calendar.YEAR) 565 if (reg[0][4] != null) 566 ed2 += "-" + String.format("%02d", cal.get(Calendar.MONTH)+1) 567 if (reg[0][6] != null) 568 ed2 += "-" + String.format("%02d", cal.get(Calendar.DAY_OF_MONTH)) 569 } 570 String ef2 = ed2.replaceAll("\\A-;","").replaceAll(";-\\z","").replaceAll("\\A([0-9-]+);\\1\\z","\$1") 646 String ed2 = ed; 647 Matcher m = pattern.matcher(ed); 648 if (m.matches()) { 649 Calendar cal = Calendar.getInstance(); 650 cal.set(Integer.valueOf(m.group(2)), 651 m.group(4) == null ? 0 : Integer.valueOf(m.group(4))-1, 652 m.group(6) == null ? 1 : Integer.valueOf(m.group(6))); 653 cal.add(Calendar.DAY_OF_MONTH, -1); 654 ed2 = m.group(1) + cal.get(Calendar.YEAR); 655 if (m.group(4) != null) 656 ed2 += "-" + String.format("%02d", cal.get(Calendar.MONTH)+1); 657 if (m.group(6) != null) 658 ed2 += "-" + String.format("%02d", cal.get(Calendar.DAY_OF_MONTH)); 659 } 660 String ef2 = ed2.replaceAll("\\A-;","").replaceAll(";-\\z","").replaceAll("\\A([0-9-]+);\\1\\z", "$1"); 571 661 if (!ed.equals(jd) && !ef.equals(jd) && !ed2.equals(jd) && !ef2.equals(jd)) { 572 String t = "' ${ed}'"662 String t = "'"+ed+"'"; 573 663 if (!ed.equals(ef)) { 574 t += " or ' ${ef}'"664 t += " or '"+ef+"'"; 575 665 } 576 666 if (jd.isEmpty()) { 577 myprintln "- Missing JOSM date (${t}): ${getDescription(j)}"667 myprintln("- Missing JOSM date ("+t+"): "+getDescription(j)); 578 668 } else if (!ed.isEmpty()) { 579 myprintln "* Date differs ('${t}' != '${jd}'): ${getDescription(j)}" 580 } else if (!options.nomissingeli) { 581 myprintln "+ Missing ELI date ('${jd}'): ${getDescription(j)}" 582 } 583 } 584 } 585 myprintln "*** Same URL, but different information: ***" 586 for (def url : eliUrls.keySet()) { 587 if (!josmUrls.containsKey(url)) continue 588 def e = eliUrls.get(url) 589 def j = josmUrls.get(url) 590 591 def et = getDescriptions(e) 592 def jt = getDescriptions(j) 593 et = (et.size() > 0) ? et["en"] : "" 594 jt = (jt.size() > 0) ? jt["en"] : "" 669 myprintln("* Date differs ('"+t+"' != '"+jd+"'): "+getDescription(j)); 670 } else if (!optionNoEli) { 671 myprintln("+ Missing ELI date ('"+jd+"'): "+getDescription(j)); 672 } 673 } 674 } 675 myprintln("*** Same URL, but different information: ***"); 676 for (String url : eliUrls.keySet()) { 677 if (!josmUrls.containsKey(url)) continue; 678 JsonObject e = eliUrls.get(url); 679 ImageryInfo j = josmUrls.get(url); 680 681 String et = getDescriptions(e).getOrDefault("en", ""); 682 String jt = getDescriptions(j).getOrDefault("en", ""); 595 683 if (!et.equals(jt)) { 596 if ( !jt) {597 myprintln "- Missing JOSM description (${et}): ${getDescription(j)}"598 } else if ( et) {599 myprintln "* Description differs ('${et}' != '${jt}'): ${getDescription(j)}"600 } else if (!option s.nomissingeli) {601 myprintln "+ Missing ELI description ('${jt}'): ${getDescription(j)}"602 } 603 } 604 605 et = getPermissionReferenceUrl(e) 606 jt = getPermissionReferenceUrl(j) 607 def jt2 = getTermsOfUseUrl(j)608 if ( !jt) jt = jt2609 if (! et.equals(jt)) {610 if ( !jt) {611 myprintln "- Missing JOSM license URL (${et}): ${getDescription(j)}"612 } else if ( et) {613 def ethttps = et.replace("http:","https:")614 if (!jt2|| !(jt2.equals(ethttps) || jt2.equals(et+"/") || jt2.equals(ethttps+"/"))) {615 if (jt.equals(ethttps) || jt.equals(et+"/") || jt.equals(ethttps+"/")) {616 myprintln "+ License URL differs ('${et}' != '${jt}'): ${getDescription(j)}"684 if (jt.isEmpty()) { 685 myprintln("- Missing JOSM description ("+et+"): "+getDescription(j)); 686 } else if (!et.isEmpty()) { 687 myprintln("* Description differs ('"+et+"' != '"+jt+"'): "+getDescription(j)); 688 } else if (!optionNoEli) { 689 myprintln("+ Missing ELI description ('"+jt+"'): "+getDescription(j)); 690 } 691 } 692 693 et = getPermissionReferenceUrl(e); 694 jt = getPermissionReferenceUrl(j); 695 String jt2 = getTermsOfUseUrl(j); 696 if (isBlank(jt)) jt = jt2; 697 if (!Objects.equals(et, jt)) { 698 if (isBlank(jt)) { 699 myprintln("- Missing JOSM license URL ("+et+"): "+getDescription(j)); 700 } else if (isNotBlank(et)) { 701 String ethttps = et.replace("http:", "https:"); 702 if (isBlank(jt2) || !(jt2.equals(ethttps) || jt2.equals(et+"/") || jt2.equals(ethttps+"/"))) { 703 if (jt.equals(ethttps) || jt.equals(et+"/") || jt.equals(ethttps+"/")) { 704 myprintln("+ License URL differs ('"+et+"' != '"+jt+"'): "+getDescription(j)); 617 705 } else { 618 def ja = getAttributionUrl(j)619 if (ja && (ja.equals(et) || ja.equals(ethttps) || ja.equals(et+"/") || ja.equals(ethttps+"/"))) {620 myprintln "+ ELI License URL in JOSM Attribution: ${getDescription(j)}"706 String ja = getAttributionUrl(j); 707 if (ja != null && (ja.equals(et) || ja.equals(ethttps) || ja.equals(et+"/") || ja.equals(ethttps+"/"))) { 708 myprintln("+ ELI License URL in JOSM Attribution: "+getDescription(j)); 621 709 } else { 622 myprintln "* License URL differs ('${et}' != '${jt}'): ${getDescription(j)}"710 myprintln("* License URL differs ('"+et+"' != '"+jt+"'): "+getDescription(j)); 623 711 } 624 712 } 625 713 } 626 } else if (!option s.nomissingeli) {627 myprintln "+ Missing ELI license URL ('${jt}'): ${getDescription(j)}"628 } 629 } 630 631 et = getAttributionUrl(e) 632 jt = getAttributionUrl(j) 633 if (! et.equals(jt)) {634 if ( !jt) {635 myprintln "- Missing JOSM attribution URL (${et}): ${getDescription(j)}"636 } else if ( et) {637 def ethttps = et.replace("http:","https:")638 if (jt.equals(ethttps) || jt.equals(et+"/") || jt.equals(ethttps+"/")) {639 myprintln "+ Attribution URL differs ('${et}' != '${jt}'): ${getDescription(j)}"714 } else if (!optionNoEli) { 715 myprintln("+ Missing ELI license URL ('"+jt+"'): "+getDescription(j)); 716 } 717 } 718 719 et = getAttributionUrl(e); 720 jt = getAttributionUrl(j); 721 if (!Objects.equals(et, jt)) { 722 if (isBlank(jt)) { 723 myprintln("- Missing JOSM attribution URL ("+et+"): "+getDescription(j)); 724 } else if (isNotBlank(et)) { 725 String ethttps = et.replace("http:","https:"); 726 if (jt.equals(ethttps) || jt.equals(et+"/") || jt.equals(ethttps+"/")) { 727 myprintln("+ Attribution URL differs ('"+et+"' != '"+jt+"'): "+getDescription(j)); 640 728 } else { 641 myprintln "* Attribution URL differs ('${et}' != '${jt}'): ${getDescription(j)}" 642 } 643 } else if (!options.nomissingeli) { 644 myprintln "+ Missing ELI attribution URL ('${jt}'): ${getDescription(j)}" 645 } 646 } 647 648 et = getAttributionText(e) 649 jt = getAttributionText(j) 650 if (!et.equals(jt)) { 651 if (!jt) { 652 myprintln "- Missing JOSM attribution text (${et}): ${getDescription(j)}" 653 } else if (et) { 654 myprintln "* Attribution text differs ('${et}' != '${jt}'): ${getDescription(j)}" 655 } else if (!options.nomissingeli) { 656 myprintln "+ Missing ELI attribution text ('${jt}'): ${getDescription(j)}" 657 } 658 } 659 660 et = getProjections(e) 661 jt = getProjections(j) 662 if (et) { et = new LinkedList(et); Collections.sort(et); et = String.join(" ", et) } 663 if (jt) { jt = new LinkedList(jt); Collections.sort(jt); jt = String.join(" ", jt) } 664 if (!et.equals(jt)) { 665 if (!jt) { 666 def t = getType(e) 667 if(t == "wms_endpoint" || t == "tms") { 668 myprintln "+ ELI projections for type ${t}: ${getDescription(j)}" 669 } 670 else { 671 myprintln "- Missing JOSM projections (${et}): ${getDescription(j)}" 672 } 673 } else if (et) { 674 if("EPSG:3857 EPSG:4326".equals(et) || "EPSG:3857".equals(et) || "EPSG:4326".equals(et)) { 675 myprintln "+ ELI has minimal projections ('${et}' != '${jt}'): ${getDescription(j)}" 729 myprintln("* Attribution URL differs ('"+et+"' != '"+jt+"'): "+getDescription(j)); 730 } 731 } else if (!optionNoEli) { 732 myprintln("+ Missing ELI attribution URL ('"+jt+"'): "+getDescription(j)); 733 } 734 } 735 736 et = getAttributionText(e); 737 jt = getAttributionText(j); 738 if (!Objects.equals(et, jt)) { 739 if (isBlank(jt)) { 740 myprintln("- Missing JOSM attribution text ("+et+"): "+getDescription(j)); 741 } else if (isNotBlank(et)) { 742 myprintln("* Attribution text differs ('"+et+"' != '"+jt+"'): "+getDescription(j)); 743 } else if (!optionNoEli) { 744 myprintln("+ Missing ELI attribution text ('"+jt+"'): "+getDescription(j)); 745 } 746 } 747 748 et = getProjections(e).stream().sorted().collect(Collectors.joining(" ")); 749 jt = getProjections(j).stream().sorted().collect(Collectors.joining(" ")); 750 if (!Objects.equals(et, jt)) { 751 if (isBlank(jt)) { 752 String t = getType(e); 753 if ("wms_endpoint".equals(t) || "tms".equals(t)) { 754 myprintln("+ ELI projections for type "+t+": "+getDescription(j)); 676 755 } else { 677 myprintln "* Projections differ ('${et}' != '${jt}'): ${getDescription(j)}" 678 } 679 } else if (!options.nomissingeli && !getType(e).equals("tms")) { 680 myprintln "+ Missing ELI projections ('${jt}'): ${getDescription(j)}" 681 } 682 } 683 684 et = getDefault(e) 685 jt = getDefault(j) 686 if (!et.equals(jt)) { 687 if (!jt) { 688 myprintln "- Missing JOSM default: ${getDescription(j)}" 689 } else if (!options.nomissingeli) { 690 myprintln "+ Missing ELI default: ${getDescription(j)}" 691 } 692 } 693 et = getOverlay(e) 694 jt = getOverlay(j) 695 if (!et.equals(jt)) { 696 if (!jt) { 697 myprintln "- Missing JOSM overlay flag: ${getDescription(j)}" 698 } else if (!options.nomissingeli) { 699 myprintln "+ Missing ELI overlay flag: ${getDescription(j)}" 700 } 701 } 702 } 703 myprintln "*** Mismatching shapes: ***" 704 for (def url : josmUrls.keySet()) { 705 def j = josmUrls.get(url) 706 def num = 1 707 for (def shape : getShapes(j)) { 708 def p = shape.getPoints() 709 if(!p[0].equals(p[p.size()-1])) { 710 myprintln "+++ JOSM shape $num unclosed: ${getDescription(j)}" 711 } 712 for (def nump = 1; nump < p.size(); ++nump) { 713 if (p[nump-1] == p[nump]) { 714 myprintln "+++ JOSM shape $num double point at ${nump-1}: ${getDescription(j)}" 715 } 716 } 717 ++num 718 } 719 } 720 for (def url : eliUrls.keySet()) { 721 def e = eliUrls.get(url) 722 def num = 1 723 def s 756 myprintln("- Missing JOSM projections ("+et+"): "+getDescription(j)); 757 } 758 } else if (isNotBlank(et)) { 759 if ("EPSG:3857 EPSG:4326".equals(et) || "EPSG:3857".equals(et) || "EPSG:4326".equals(et)) { 760 myprintln("+ ELI has minimal projections ('"+et+"' != '"+jt+"'): "+getDescription(j)); 761 } else { 762 myprintln("* Projections differ ('"+et+"' != '"+jt+"'): "+getDescription(j)); 763 } 764 } else if (!optionNoEli && !"tms".equals(getType(e))) { 765 myprintln("+ Missing ELI projections ('"+jt+"'): "+getDescription(j)); 766 } 767 } 768 769 boolean ed = getDefault(e); 770 boolean jd = getDefault(j); 771 if (ed != jd) { 772 if (!jd) { 773 myprintln("- Missing JOSM default: "+getDescription(j)); 774 } else if (!optionNoEli) { 775 myprintln("+ Missing ELI default: "+getDescription(j)); 776 } 777 } 778 boolean eo = getOverlay(e); 779 boolean jo = getOverlay(j); 780 if (eo != jo) { 781 if (!jo) { 782 myprintln("- Missing JOSM overlay flag: "+getDescription(j)); 783 } else if (!optionNoEli) { 784 myprintln("+ Missing ELI overlay flag: "+getDescription(j)); 785 } 786 } 787 } 788 myprintln("*** Mismatching shapes: ***"); 789 for (String url : josmUrls.keySet()) { 790 ImageryInfo j = josmUrls.get(url); 791 int num = 1; 792 for (Shape shape : getShapes(j)) { 793 List<Coordinate> p = shape.getPoints(); 794 if(!p.get(0).equals(p.get(p.size()-1))) { 795 myprintln("+++ JOSM shape "+num+" unclosed: "+getDescription(j)); 796 } 797 for (int nump = 1; nump < p.size(); ++nump) { 798 if (Objects.equals(p.get(nump-1), p.get(nump))) { 799 myprintln("+++ JOSM shape "+num+" double point at "+(nump-1)+": "+getDescription(j)); 800 } 801 } 802 ++num; 803 } 804 } 805 for (String url : eliUrls.keySet()) { 806 JsonObject e = eliUrls.get(url); 807 int num = 1; 808 List<Shape> s = null; 724 809 try { 725 s = getShapes(e) 726 for ( defshape : s) {727 def p = shape.getPoints()728 if(!p [0].equals(p[p.size()-1]) && !options.nomissingeli) {729 myprintln "+++ ELI shape $num unclosed: ${getDescription(e)}"730 } 731 for ( defnump = 1; nump < p.size(); ++nump) {732 if ( p[nump-1] == p[nump]) {733 myprintln "+++ ELI shape $num double point at ${nump-1}: ${getDescription(e)}"810 s = getShapes(e); 811 for (Shape shape : s) { 812 List<Coordinate> p = shape.getPoints(); 813 if(!p.get(0).equals(p.get(p.size()-1)) && !optionNoEli) { 814 myprintln("+++ ELI shape "+num+" unclosed: "+getDescription(e)); 815 } 816 for (int nump = 1; nump < p.size(); ++nump) { 817 if (Objects.equals(p.get(nump-1), p.get(nump))) { 818 myprintln("+++ ELI shape "+num+" double point at "+(nump-1)+": "+getDescription(e)); 734 819 } 735 820 } 736 ++num 737 } 738 } catch (IllegalArgumentException err) {739 def desc = getDescription(e)740 myprintln("* Invalid data in ELI geometry for $desc: ${err.getMessage()}")821 ++num; 822 } 823 } catch (IllegalArgumentException err) { 824 String desc = getDescription(e); 825 myprintln("* Invalid data in ELI geometry for "+desc+": "+err.getMessage()); 741 826 } 742 827 if (s == null || !josmUrls.containsKey(url)) { 743 continue 744 } 745 def j = josmUrls.get(url)746 def js = getShapes(j)747 if (!s.size() && js.size()) {748 if (!options.nomissingeli) {749 myprintln "+ No ELI shape: ${getDescription(j)}"750 } 751 } else if( !js.size() && s.size()) {828 continue; 829 } 830 ImageryInfo j = josmUrls.get(url); 831 List<Shape> js = getShapes(j); 832 if (s.isEmpty() && !js.isEmpty()) { 833 if (!optionNoEli) { 834 myprintln("+ No ELI shape: "+getDescription(j)); 835 } 836 } else if(js.isEmpty() && !s.isEmpty()) { 752 837 // don't report boundary like 5 point shapes as difference 753 if (s.size() != 1 || s [0].getPoints().size() != 5) {754 myprintln "- No JOSM shape: ${getDescription(j)}"838 if (s.size() != 1 || s.get(0).getPoints().size() != 5) { 839 myprintln("- No JOSM shape: "+getDescription(j)); 755 840 } 756 841 } else if(s.size() != js.size()) { 757 myprintln "* Different number of shapes (${s.size()} != ${js.size()}): ${getDescription(j)}"842 myprintln("* Different number of shapes ("+s.size()+" != "+js.size()+"): "+getDescription(j)); 758 843 } else { 759 boolean[] edone = new boolean[s.size()] 760 boolean[] jdone = new boolean[js.size()] 761 for (defenums = 0; enums < s.size(); ++enums) {762 def ep = s[enums].getPoints()763 for (defjnums = 0; jnums < js.size() && !edone[enums]; ++jnums) {764 def jp = js[jnums].getPoints()765 if (ep.size() == jp.size() && !jdone[jnums]) {844 boolean[] edone = new boolean[s.size()]; 845 boolean[] jdone = new boolean[js.size()]; 846 for (int enums = 0; enums < s.size(); ++enums) { 847 List<Coordinate> ep = s.get(enums).getPoints(); 848 for (int jnums = 0; jnums < js.size() && !edone[enums]; ++jnums) { 849 List<Coordinate> jp = js.get(jnums).getPoints(); 850 if (ep.size() == jp.size() && !jdone[jnums]) { 766 851 boolean err = false; 767 for( defnump = 0; nump < ep.size() && !err; ++nump) {768 def ept = ep[nump]769 def jpt = jp[nump]852 for(int nump = 0; nump < ep.size() && !err; ++nump) { 853 Coordinate ept = ep.get(nump); 854 Coordinate jpt = jp.get(nump); 770 855 if(Math.abs(ept.getLat()-jpt.getLat()) > 0.00001 || Math.abs(ept.getLon()-jpt.getLon()) > 0.00001) 771 err = true 856 err = true; 772 857 } 773 858 if(!err) { 774 edone[enums] = true 775 jdone[jnums] = true 776 break 859 edone[enums] = true; 860 jdone[jnums] = true; 861 break; 777 862 } 778 863 } 779 864 } 780 865 } 781 for (defenums = 0; enums < s.size(); ++enums) {782 def ep = s[enums].getPoints()783 for (defjnums = 0; jnums < js.size() && !edone[enums]; ++jnums) {784 def jp = js[jnums].getPoints()785 if (ep.size() == jp.size() && !jdone[jnums]) {866 for (int enums = 0; enums < s.size(); ++enums) { 867 List<Coordinate> ep = s.get(enums).getPoints(); 868 for (int jnums = 0; jnums < js.size() && !edone[enums]; ++jnums) { 869 List<Coordinate> jp = js.get(jnums).getPoints(); 870 if (ep.size() == jp.size() && !jdone[jnums]) { 786 871 boolean err = false; 787 for(def nump = 0; nump < ep.size() && !err; ++nump) { 788 def ept = ep[nump] 789 def jpt = jp[nump] 790 if(Math.abs(ept.getLat()-jpt.getLat()) > 0.00001 || Math.abs(ept.getLon()-jpt.getLon()) > 0.00001) { 791 def numtxt = ((enums == jnums) ? "${enums+1}" : "${enums+1}/${jnums+1}") 792 myprintln "* Different coordinate for point ${nump+1} of shape $numtxt: ${getDescription(j)}" 793 break 872 for (int nump = 0; nump < ep.size() && !err; ++nump) { 873 Coordinate ept = ep.get(nump); 874 Coordinate jpt = jp.get(nump); 875 if (Math.abs(ept.getLat()-jpt.getLat()) > 0.00001 || Math.abs(ept.getLon()-jpt.getLon()) > 0.00001) { 876 String numtxt = Integer.toString(enums+1); 877 if (enums != jnums) { 878 numtxt += '/' + Integer.toString(jnums+1); 879 } 880 myprintln("* Different coordinate for point "+(nump+1)+" of shape "+numtxt+": "+getDescription(j)); 881 break; 794 882 } 795 883 } 796 edone[enums] = true 797 jdone[jnums] = true 798 break 884 edone[enums] = true; 885 jdone[jnums] = true; 886 break; 799 887 } 800 888 } 801 889 } 802 for(def enums = 0; enums < s.size(); ++enums) { 803 def ep = s[enums].getPoints() 804 for(def jnums = 0; jnums < js.size() && !edone[enums]; ++jnums) { 805 def jp = js[jnums].getPoints() 806 if(!jdone[jnums]) { 807 def numtxt = ((enums == jnums) ? "${enums+1}" : "${enums+1}/${jnums+1}") 808 myprintln "* Different number of points for shape $numtxt (${ep.size()} ! = ${jp.size()})): ${getDescription(j)}" 809 edone[enums] = true 810 jdone[jnums] = true 811 break 890 for (int enums = 0; enums < s.size(); ++enums) { 891 List<Coordinate> ep = s.get(enums).getPoints(); 892 for (int jnums = 0; jnums < js.size() && !edone[enums]; ++jnums) { 893 List<Coordinate> jp = js.get(jnums).getPoints(); 894 if (!jdone[jnums]) { 895 String numtxt = Integer.toString(enums+1); 896 if (enums != jnums) { 897 numtxt += '/' + Integer.toString(jnums+1); 898 } 899 myprintln("* Different number of points for shape "+numtxt+" ("+ep.size()+" ! = "+jp.size()+")): "+getDescription(j)); 900 edone[enums] = true; 901 jdone[jnums] = true; 902 break; 812 903 } 813 904 } … … 815 906 } 816 907 } 817 myprintln "*** Mismatching icons: ***"818 for ( defurl : eliUrls.keySet()) {819 def e = eliUrls.get(url)908 myprintln("*** Mismatching icons: ***"); 909 for (String url : eliUrls.keySet()) { 910 JsonObject e = eliUrls.get(url); 820 911 if (!josmUrls.containsKey(url)) { 821 continue 822 } 823 def j = josmUrls.get(url) 824 def ij = getIcon(j) 825 def ie = getIcon(e) 826 if(ij != null && ie == null) { 827 if(!options.nomissingeli) { 828 myprintln "+ No ELI icon: ${getDescription(j)}" 829 } 830 } else if(ij == null && ie != null) { 831 myprintln "- No JOSM icon: ${getDescription(j)}" 832 } else if(!ij.equals(ie) && !( 912 continue; 913 } 914 ImageryInfo j = josmUrls.get(url); 915 String ij = getIcon(j); 916 String ie = getIcon(e); 917 boolean ijok = isNotBlank(ij); 918 boolean ieok = isNotBlank(ie); 919 if (ijok && !ieok) { 920 if (!optionNoEli) { 921 myprintln("+ No ELI icon: "+getDescription(j)); 922 } 923 } else if (!ijok && ieok) { 924 myprintln("- No JOSM icon: "+getDescription(j)); 925 } else if (ijok && ieok && !Objects.equals(ij, ie) && !( 833 926 (ie.startsWith("https://osmlab.github.io/editor-layer-index/") 834 927 || ie.startsWith("https://raw.githubusercontent.com/osmlab/editor-layer-index/")) && 835 928 ij.startsWith("data:"))) { 836 def iehttps = ie.replace("http:","https:")837 if (ij.equals(iehttps)) {838 myprintln "+ Different icons: ${getDescription(j)}"929 String iehttps = ie.replace("http:","https:"); 930 if (ij.equals(iehttps)) { 931 myprintln("+ Different icons: "+getDescription(j)); 839 932 } else { 840 myprintln "* Different icons: ${getDescription(j)}"841 } 842 } 843 } 844 myprintln "*** Miscellaneous checks: ***"845 def josmIds = new HashMap<String, ImageryInfo>()846 def all = Projections.getAllProjectionCodes()933 myprintln("* Different icons: "+getDescription(j)); 934 } 935 } 936 } 937 myprintln("*** Miscellaneous checks: ***"); 938 Map<String, ImageryInfo> josmIds = new HashMap<>(); 939 Collection<String> all = Projections.getAllProjectionCodes(); 847 940 DomainValidator dv = DomainValidator.getInstance(); 848 for (def url : josmUrls.keySet()) { 849 def j = josmUrls.get(url) 850 def id = getId(j) 851 if("wms".equals(getType(j))) { 852 if(!getProjections(j)) { 853 myprintln "* WMS without projections: ${getDescription(j)}" 941 for (String url : josmUrls.keySet()) { 942 ImageryInfo j = josmUrls.get(url); 943 String id = getId(j); 944 if ("wms".equals(getType(j))) { 945 String urlLc = url.toLowerCase(Locale.ENGLISH); 946 if (getProjections(j).isEmpty()) { 947 myprintln("* WMS without projections: "+getDescription(j)); 854 948 } else { 855 def unsupported = new LinkedList<String>()856 def old = new LinkedList<String>()857 for ( defp : getProjectionsUnstripped(j)) {858 if ("CRS:84".equals(p)) {859 if (!(url =~ /(?i)version=1\.3/)) {860 myprintln "* CRS:84 without WMS 1.3: ${getDescription(j)}"949 List<String> unsupported = new LinkedList<>(); 950 List<String> old = new LinkedList<>(); 951 for (String p : getProjectionsUnstripped(j)) { 952 if ("CRS:84".equals(p)) { 953 if (!urlLc.contains("version=1.3")) { 954 myprintln("* CRS:84 without WMS 1.3: "+getDescription(j)); 861 955 } 862 } else if (oldproj.containsKey(p)) {863 old.add(p) 864 } else if (!all.contains(p) && !ignoreproj.contains(p)) {865 unsupported.add(p) 956 } else if (oldproj.containsKey(p)) { 957 old.add(p); 958 } else if (!all.contains(p) && !ignoreproj.contains(p)) { 959 unsupported.add(p); 866 960 } 867 961 } 868 if (unsupported) { 869 def s = String.join(", ", unsupported) 870 myprintln "* Projections ${s} not supported by JOSM: ${getDescription(j)}" 871 } 872 for (def o : old) { 873 myprintln "* Projection ${o} is an old unsupported code and has been replaced by ${oldproj.get(o)}: ${getDescription(j)}" 874 } 875 } 876 if((url =~ /(?i)version=1\.3/) && !(url =~ /[Cc][Rr][Ss]=\{proj\}/)) { 877 myprintln "* WMS 1.3 with strange CRS specification: ${getDescription(j)}" 878 } 879 if((url =~ /(?i)version=1\.1/) && !(url =~ /[Ss][Rr][Ss]=\{proj\}/)) { 880 myprintln "* WMS 1.1 with strange SRS specification: ${getDescription(j)}" 881 } 882 } 883 def urls = new LinkedList<String>() 884 if(!"scanex".equals(getType(j))) { 885 urls += url 886 } 887 def jt = getPermissionReferenceUrl(j) 888 if(jt && !"Public Domain".equals(jt)) 889 urls += jt 890 jt = getTermsOfUseUrl(j) 891 if(jt) 892 urls += jt 893 jt = getAttributionUrl(j) 894 if(jt) 895 urls += jt 896 jt = getIcon(j) 897 if(jt && !(jt =~ /^data:image\/png;base64,/)) 898 urls += jt 899 for(def u : urls) { 900 def m = u =~ /^https?:\/\/([^\/]+?)(:\d+)?\// 901 if(!m || u =~ /[ \t]+$/) 902 myprintln "* Strange URL '${u}': ${getDescription(j)}" 903 else { 904 def domain = m[0][1].replaceAll("\\{switch:.*\\}","x") 905 def port = m[0][2] 906 if (!(domain =~ /^\d+\.\d+\.\d+\.\d+$/) && !dv.isValid(domain)) 907 myprintln "* Strange Domain '${domain}': ${getDescription(j)}" 908 else if (port != null && (port == ":80" || port == ":443")) { 909 myprintln "* Useless port '${port}': ${getDescription(j)}" 910 } 911 } 912 } 913 914 if(josmMirrors.containsKey(url)) { 915 continue 916 } 917 if(id == null) { 918 myprintln "* No JOSM-ID: ${getDescription(j)}" 919 } else if(josmIds.containsKey(id)) { 920 myprintln "* JOSM-ID ${id} not unique: ${getDescription(j)}" 962 if (!unsupported.isEmpty()) { 963 myprintln("* Projections "+String.join(", ", unsupported)+" not supported by JOSM: "+getDescription(j)); 964 } 965 for (String o : old) { 966 myprintln("* Projection "+o+" is an old unsupported code and has been replaced by "+oldproj.get(o)+": "+getDescription(j)); 967 } 968 } 969 if (urlLc.contains("version=1.3") && !urlLc.contains("crs={proj}")) { 970 myprintln("* WMS 1.3 with strange CRS specification: "+getDescription(j)); 971 } else if (urlLc.contains("version=1.1") && !urlLc.contains("srs={proj}")) { 972 myprintln("* WMS 1.1 with strange SRS specification: "+getDescription(j)); 973 } 974 } 975 List<String> urls = new LinkedList<>(); 976 if (!"scanex".equals(getType(j))) { 977 urls.add(url); 978 } 979 String jt = getPermissionReferenceUrl(j); 980 if (isNotBlank(jt) && !"Public Domain".equalsIgnoreCase(jt)) 981 urls.add(jt); 982 jt = getTermsOfUseUrl(j); 983 if (isNotBlank(jt)) 984 urls.add(jt); 985 jt = getAttributionUrl(j); 986 if (isNotBlank(jt)) 987 urls.add(jt); 988 jt = getIcon(j); 989 if (isNotBlank(jt) && !jt.startsWith("data:image/png;base64,")) 990 urls.add(jt); 991 Pattern patternU = Pattern.compile("^https?://([^/]+?)(:\\d+)?/.*"); 992 for (String u : urls) { 993 Matcher m = patternU.matcher(u); 994 if (!m.matches() || u.matches(".*[ \t]+$")) { 995 myprintln("* Strange URL '"+u+"': "+getDescription(j)); 996 } else { 997 String domain = m.group(1).replaceAll("\\{switch:.*\\}","x"); 998 String port = m.group(2); 999 if (!(domain.matches("^\\d+\\.\\d+\\.\\d+\\.\\d+$")) && !dv.isValid(domain)) 1000 myprintln("* Strange Domain '"+domain+"': "+getDescription(j)); 1001 else if (":80".equals(port) || ":443".equals(port)) { 1002 myprintln("* Useless port '"+port+"': "+getDescription(j)); 1003 } 1004 } 1005 } 1006 1007 if (josmMirrors.containsKey(url)) { 1008 continue; 1009 } 1010 if (isBlank(id)) { 1011 myprintln("* No JOSM-ID: "+getDescription(j)); 1012 } else if (josmIds.containsKey(id)) { 1013 myprintln("* JOSM-ID "+id+" not unique: "+getDescription(j)); 921 1014 } else { 922 josmIds.put(id, j) 923 } 924 def d = getDate(j) 925 if(!d.isEmpty()) { 926 def reg = (d =~ /^(-|(\d\d\d\d)(-(\d\d)(-(\d\d))?)?)(;(-|(\d\d\d\d)(-(\d\d)(-(\d\d))?)?))?$/) 927 if(reg == null || reg.count != 1) { 928 myprintln "* JOSM-Date '${d}' is strange: ${getDescription(j)}" 1015 josmIds.put(id, j); 1016 } 1017 String d = getDate(j); 1018 if (isNotBlank(d)) { 1019 Pattern patternD = Pattern.compile("^(-|(\\d\\d\\d\\d)(-(\\d\\d)(-(\\d\\d))?)?)(;(-|(\\d\\d\\d\\d)(-(\\d\\d)(-(\\d\\d))?)?))?$"); 1020 Matcher m = patternD.matcher(d); 1021 if (!m.matches()) { 1022 myprintln("* JOSM-Date '"+d+"' is strange: "+getDescription(j)); 929 1023 } else { 930 1024 try { 931 def first = verifyDate(reg[0][2],reg[0][4],reg[0][6])932 def second = verifyDate(reg[0][9],reg[0][11],reg[0][13])933 if (second.compareTo(first) < 0) {934 myprintln "* JOSM-Date '${d}' is strange (second earlier than first): ${getDescription(j)}"1025 Date first = verifyDate(m.group(2), m.group(4), m.group(6)); 1026 Date second = verifyDate(m.group(9), m.group(11), m.group(13)); 1027 if (second.compareTo(first) < 0) { 1028 myprintln("* JOSM-Date '"+d+"' is strange (second earlier than first): "+getDescription(j)); 935 1029 } 936 1030 } 937 1031 catch (Exception e) { 938 myprintln "* JOSM-Date '${d}' is strange (${e.getMessage()}): ${getDescription(j)}" 939 } 940 } 941 } 942 if(getAttributionUrl(j) && !getAttributionText(j)) { 943 myprintln "* Attribution link without text: ${getDescription(j)}" 944 } 945 if(getLogoUrl(j) && !getLogoImage(j)) { 946 myprintln "* Logo link without image: ${getDescription(j)}" 947 } 948 if(getTermsOfUseText(j) && !getTermsOfUseUrl(j)) { 949 myprintln "* Terms of Use text without link: ${getDescription(j)}" 950 } 951 def js = getShapes(j) 952 if(js.size()) { 953 def minlat = 1000 954 def minlon = 1000 955 def maxlat = -1000 956 def maxlon = -1000 957 for(def s: js) { 958 for(def p: s.getPoints()) { 959 def lat = p.getLat() 960 def lon = p.getLon() 961 if(lat > maxlat) maxlat = lat 962 if(lon > maxlon) maxlon = lon 963 if(lat < minlat) minlat = lat 964 if(lon < minlon) minlon = lon 965 } 966 } 967 def b = j.getBounds() 968 if(b.getMinLat() != minlat || b.getMinLon() != minlon || b.getMaxLat() != maxlat || b.getMaxLon() != maxlon) { 969 myprintln "* Bounds do not match shape (is ${b.getMinLat()},${b.getMinLon()},${b.getMaxLat()},${b.getMaxLon()}, calculated <bounds min-lat='${minlat}' min-lon='${minlon}' max-lat='${maxlat}' max-lon='${maxlon}'>): ${getDescription(j)}" 970 } 971 } 972 def cat = getCategory(j) 973 if(cat == null) { 974 myprintln "* No category: ${getDescription(j)}" 975 } else if(cat != "photo" && cat != "map" && cat != "historicmap" && cat != "osmbasedmap" && cat != "historicphoto" && cat != "other") { 976 myprintln "* Strange category ${cat}: ${getDescription(j)}" 977 } 978 } 979 } 980 981 /** 1032 myprintln("* JOSM-Date '"+d+"' is strange ("+e.getMessage()+"): "+getDescription(j)); 1033 } 1034 } 1035 } 1036 if (isNotBlank(getAttributionUrl(j)) && isBlank(getAttributionText(j))) { 1037 myprintln("* Attribution link without text: "+getDescription(j)); 1038 } 1039 if (isNotBlank(getLogoUrl(j)) && isBlank(getLogoImage(j))) { 1040 myprintln("* Logo link without image: "+getDescription(j)); 1041 } 1042 if (isNotBlank(getTermsOfUseText(j)) && isBlank(getTermsOfUseUrl(j))) { 1043 myprintln("* Terms of Use text without link: "+getDescription(j)); 1044 } 1045 List<Shape> js = getShapes(j); 1046 if (!js.isEmpty()) { 1047 double minlat = 1000; 1048 double minlon = 1000; 1049 double maxlat = -1000; 1050 double maxlon = -1000; 1051 for (Shape s: js) { 1052 for (Coordinate p: s.getPoints()) { 1053 double lat = p.getLat(); 1054 double lon = p.getLon(); 1055 if(lat > maxlat) maxlat = lat; 1056 if(lon > maxlon) maxlon = lon; 1057 if(lat < minlat) minlat = lat; 1058 if(lon < minlon) minlon = lon; 1059 } 1060 } 1061 ImageryBounds b = j.getBounds(); 1062 if (b.getMinLat() != minlat || b.getMinLon() != minlon || b.getMaxLat() != maxlat || b.getMaxLon() != maxlon) { 1063 myprintln("* Bounds do not match shape (is "+b.getMinLat()+","+b.getMinLon()+","+b.getMaxLat()+","+b.getMaxLon() 1064 + ", calculated <bounds min-lat='"+minlat+"' min-lon='"+minlon+"' max-lat='"+maxlat+"' max-lon='"+maxlon+"'>): "+getDescription(j)); 1065 } 1066 } 1067 List<String> knownCategories = Arrays.asList("photo", "map", "historicmap", "osmbasedmap", "historicphoto", "other"); 1068 String cat = getCategory(j); 1069 if (isBlank(cat)) { 1070 myprintln("* No category: "+getDescription(j)); 1071 } else if (!knownCategories.contains(cat)) { 1072 myprintln("* Strange category "+cat+": "+getDescription(j)); 1073 } 1074 } 1075 } 1076 1077 /* 982 1078 * Utility functions that allow uniform access for both ImageryInfo and JsonObject. 983 1079 */ 1080 984 1081 static String getUrl(Object e) { 985 if (e instanceof ImageryInfo) return e.url 986 return e.get("properties").getString("url") 987 } 1082 if (e instanceof ImageryInfo) return ((ImageryInfo) e).getUrl(); 1083 return ((Map<String, JsonObject>) e).get("properties").getString("url"); 1084 } 1085 988 1086 static String getUrlStripped(Object e) { 989 return getUrl(e).replaceAll("\\?(apikey|access_token)=.*","") 990 } 1087 return getUrl(e).replaceAll("\\?(apikey|access_token)=.*",""); 1088 } 1089 991 1090 static String getDate(Object e) { 992 if (e instanceof ImageryInfo) return e.date ? e.date : ""993 def p = e.get("properties")994 def start = p.containsKey("start_date") ? p.getString("start_date") : ""995 def end = p.containsKey("end_date") ? p.getString("end_date") : ""1091 if (e instanceof ImageryInfo) return ((ImageryInfo) e).getDate() != null ? ((ImageryInfo) e).getDate() : ""; 1092 JsonObject p = ((Map<String, JsonObject>) e).get("properties"); 1093 String start = p.containsKey("start_date") ? p.getString("start_date") : ""; 1094 String end = p.containsKey("end_date") ? p.getString("end_date") : ""; 996 1095 if(!start.isEmpty() && !end.isEmpty()) 997 return start+";"+end 1096 return start+";"+end; 998 1097 else if(!start.isEmpty()) 999 return start+";-" 1098 return start+";-"; 1000 1099 else if(!end.isEmpty()) 1001 return "-;"+end 1002 return "" 1003 } 1004 static Date verifyDate(String year, String month, String day) { 1005 def date 1100 return "-;"+end; 1101 return ""; 1102 } 1103 1104 static Date verifyDate(String year, String month, String day) throws ParseException { 1105 String date; 1006 1106 if(year == null) { 1007 date = "3000-01-01" 1107 date = "3000-01-01"; 1008 1108 } else { 1009 date = year + "-" + (month == null ? "01" : month) + "-" + (day == null ? "01" : day) 1010 } 1011 def df = new java.text.SimpleDateFormat("yyyy-MM-dd") 1012 df.setLenient(false) 1013 return df.parse(date) 1014 } 1109 date = year + "-" + (month == null ? "01" : month) + "-" + (day == null ? "01" : day); 1110 } 1111 SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd"); 1112 df.setLenient(false); 1113 return df.parse(date); 1114 } 1115 1015 1116 static String getId(Object e) { 1016 if (e instanceof ImageryInfo) return e.getId() 1017 return e.get("properties").getString("id") 1018 } 1117 if (e instanceof ImageryInfo) return ((ImageryInfo) e).getId(); 1118 return ((Map<String, JsonObject>) e).get("properties").getString("id"); 1119 } 1120 1019 1121 static String getName(Object e) { 1020 if (e instanceof ImageryInfo) return e.getOriginalName() 1021 return e.get("properties").getString("name") 1022 } 1023 static List<Object> getMirrors(Object e) { 1024 if (e instanceof ImageryInfo) return e.getMirrors() 1025 return [] 1026 } 1027 static List<Object> getProjections(Object e) { 1028 def r = [] 1029 def u = getProjectionsUnstripped(e) 1030 if(u) { 1031 for (def p : u) { 1032 if(!oldproj.containsKey(p) && !("CRS:84".equals(p) && !(getUrlStripped(e) =~ /(?i)version=1\.3/))) { 1033 r += p 1034 } 1035 } 1036 } 1037 return r 1038 } 1039 static List<Object> getProjectionsUnstripped(Object e) { 1040 def r 1122 if (e instanceof ImageryInfo) return ((ImageryInfo) e).getOriginalName(); 1123 return ((Map<String, JsonObject>) e).get("properties").getString("name"); 1124 } 1125 1126 static List<ImageryInfo> getMirrors(Object e) { 1127 if (e instanceof ImageryInfo) return ((ImageryInfo) e).getMirrors(); 1128 return Collections.emptyList(); 1129 } 1130 1131 static List<String> getProjections(Object e) { 1132 List<String> r = new ArrayList<>(); 1133 List<String> u = getProjectionsUnstripped(e); 1134 if (u != null) { 1135 for (String p : u) { 1136 if (!oldproj.containsKey(p) && !("CRS:84".equals(p) && !(getUrlStripped(e).matches("(?i)version=1\\.3")))) { 1137 r.add(p); 1138 } 1139 } 1140 } 1141 return r; 1142 } 1143 1144 static List<String> getProjectionsUnstripped(Object e) { 1145 List<String> r = null; 1041 1146 if (e instanceof ImageryInfo) { 1042 r = e.getServerProjections()1147 r = ((ImageryInfo) e).getServerProjections(); 1043 1148 } else { 1044 def s = e.get("properties").get("available_projections") 1045 if (s) { 1046 r = [] 1047 for (def p : s) { 1048 r += p.getString() 1049 } 1050 } 1051 } 1052 return r ? r : [] 1053 } 1149 JsonValue s = ((Map<String, JsonObject>) e).get("properties").get("available_projections"); 1150 if (s != null) { 1151 r = new ArrayList<>(); 1152 for (JsonValue p : s.asJsonArray()) { 1153 r.add(((JsonString) p).getString()); 1154 } 1155 } 1156 } 1157 return r != null ? r : Collections.emptyList(); 1158 } 1159 1054 1160 static List<Shape> getShapes(Object e) { 1055 1161 if (e instanceof ImageryInfo) { 1056 def bounds = e.getBounds()1162 ImageryBounds bounds = ((ImageryInfo) e).getBounds(); 1057 1163 if(bounds != null) { 1058 return bounds.getShapes() 1059 } 1060 return [] 1061 } 1062 def ex = e.get("geometry") 1063 if (ex != null && !JsonValue.NULL.equals(ex) && !ex.isNull("coordinates")) { 1064 def poly = ex.get("coordinates") 1065 List<Shape> l = [] 1066 for(def shapes: poly) { 1067 def s = new Shape() 1068 for(def point: shapes) { 1069 def lon = point[0].toString() 1070 def lat = point[1].toString() 1071 s.addPoint(lat, lon) 1072 } 1073 l.add(s) 1074 } 1075 return l 1076 } 1077 return [] 1078 } 1164 return bounds.getShapes(); 1165 } 1166 return Collections.emptyList(); 1167 } 1168 JsonValue ex = ((Map<String, JsonValue>) e).get("geometry"); 1169 if (ex != null && !JsonValue.NULL.equals(ex) && !ex.asJsonObject().isNull("coordinates")) { 1170 JsonArray poly = ex.asJsonObject().getJsonArray("coordinates"); 1171 List<Shape> l = new ArrayList<>(); 1172 for (JsonValue shapes: poly) { 1173 Shape s = new Shape(); 1174 for (JsonValue point: shapes.asJsonArray()) { 1175 String lon = point.asJsonArray().getJsonNumber(0).toString(); 1176 String lat = point.asJsonArray().getJsonNumber(1).toString(); 1177 s.addPoint(lat, lon); 1178 } 1179 l.add(s); 1180 } 1181 return l; 1182 } 1183 return Collections.emptyList(); 1184 } 1185 1079 1186 static String getType(Object e) { 1080 if (e instanceof ImageryInfo) return e.getImageryType().getTypeString() 1081 return e.get("properties").getString("type") 1082 } 1187 if (e instanceof ImageryInfo) return ((ImageryInfo) e).getImageryType().getTypeString(); 1188 return ((Map<String, JsonObject>) e).get("properties").getString("type"); 1189 } 1190 1083 1191 static Integer getMinZoom(Object e) { 1084 1192 if (e instanceof ImageryInfo) { 1085 int mz = e.getMinZoom()1086 return mz == 0 ? null : mz 1193 int mz = ((ImageryInfo) e).getMinZoom(); 1194 return mz == 0 ? null : mz; 1087 1195 } else { 1088 def num = e.get("properties").getJsonNumber("min_zoom") 1089 if (num == null) return null 1090 return num.intValue() 1091 } 1092 } 1196 JsonNumber num = ((Map<String, JsonObject>) e).get("properties").getJsonNumber("min_zoom"); 1197 if (num == null) return null; 1198 return num.intValue(); 1199 } 1200 } 1201 1093 1202 static Integer getMaxZoom(Object e) { 1094 1203 if (e instanceof ImageryInfo) { 1095 int mz = e.getMaxZoom()1096 return mz == 0 ? null : mz 1204 int mz = ((ImageryInfo) e).getMaxZoom(); 1205 return mz == 0 ? null : mz; 1097 1206 } else { 1098 def num = e.get("properties").getJsonNumber("max_zoom") 1099 if (num == null) return null 1100 return num.intValue() 1101 } 1102 } 1207 JsonNumber num = ((Map<String, JsonObject>) e).get("properties").getJsonNumber("max_zoom"); 1208 if (num == null) return null; 1209 return num.intValue(); 1210 } 1211 } 1212 1103 1213 static String getCountryCode(Object e) { 1104 if (e instanceof ImageryInfo) return "".equals(e.getCountryCode()) ? null : e.getCountryCode() 1105 return e.get("properties").getString("country_code", null) 1106 } 1214 if (e instanceof ImageryInfo) return "".equals(((ImageryInfo) e).getCountryCode()) ? null : ((ImageryInfo) e).getCountryCode(); 1215 return ((Map<String, JsonObject>) e).get("properties").getString("country_code", null); 1216 } 1217 1107 1218 static String getQuality(Object e) { 1108 if (e instanceof ImageryInfo) return e.isBestMarked() ? "eli-best" : null 1109 return (e.get("properties").containsKey("best") 1110 && e.get("properties").getBoolean("best")) ? "eli-best" : null 1111 } 1112 static Boolean getOverlay(Object e) { 1113 if (e instanceof ImageryInfo) return e.isOverlay() 1114 return (e.get("properties").containsKey("overlay") 1115 && e.get("properties").getBoolean("overlay")) 1116 } 1219 if (e instanceof ImageryInfo) return ((ImageryInfo) e).isBestMarked() ? "eli-best" : null; 1220 return (((Map<String, JsonObject>) e).get("properties").containsKey("best") 1221 && ((Map<String, JsonObject>) e).get("properties").getBoolean("best")) ? "eli-best" : null; 1222 } 1223 1224 static boolean getOverlay(Object e) { 1225 if (e instanceof ImageryInfo) return ((ImageryInfo) e).isOverlay(); 1226 return (((Map<String, JsonObject>) e).get("properties").containsKey("overlay") 1227 && ((Map<String, JsonObject>) e).get("properties").getBoolean("overlay")); 1228 } 1229 1117 1230 static String getIcon(Object e) { 1118 if (e instanceof ImageryInfo) return e.getIcon() 1119 return e.get("properties").getString("icon", null) 1120 } 1231 if (e instanceof ImageryInfo) return ((ImageryInfo) e).getIcon(); 1232 return ((Map<String, JsonObject>) e).get("properties").getString("icon", null); 1233 } 1234 1121 1235 static String getAttributionText(Object e) { 1122 if (e instanceof ImageryInfo) return e.getAttributionText(0, null, null) 1123 try {return e.get("properties").get("attribution").getString("text", null)} catch (NullPointerException ex) {return null} 1124 } 1236 if (e instanceof ImageryInfo) return ((ImageryInfo) e).getAttributionText(0, null, null); 1237 try { 1238 return ((Map<String, JsonObject>) e).get("properties").getJsonObject("attribution").getString("text", null); 1239 } catch (NullPointerException ex) { 1240 return null; 1241 } 1242 } 1243 1125 1244 static String getAttributionUrl(Object e) { 1126 if (e instanceof ImageryInfo) return e.getAttributionLinkURL() 1127 try {return e.get("properties").get("attribution").getString("url", null)} catch (NullPointerException ex) {return null} 1128 } 1245 if (e instanceof ImageryInfo) return ((ImageryInfo) e).getAttributionLinkURL(); 1246 try { 1247 return ((Map<String, JsonObject>) e).get("properties").getJsonObject("attribution").getString("url", null); 1248 } catch (NullPointerException ex) { 1249 return null; 1250 } 1251 } 1252 1129 1253 static String getTermsOfUseText(Object e) { 1130 if (e instanceof ImageryInfo) return e.getTermsOfUseText() 1131 return null 1132 } 1254 if (e instanceof ImageryInfo) return ((ImageryInfo) e).getTermsOfUseText(); 1255 return null; 1256 } 1257 1133 1258 static String getTermsOfUseUrl(Object e) { 1134 if (e instanceof ImageryInfo) return e.getTermsOfUseURL() 1135 return null 1136 } 1259 if (e instanceof ImageryInfo) return ((ImageryInfo) e).getTermsOfUseURL(); 1260 return null; 1261 } 1262 1137 1263 static String getCategory(Object e) { 1138 1264 if (e instanceof ImageryInfo) { 1139 return e.getImageryCategoryOriginalString() 1140 } 1141 return null 1142 } 1265 return ((ImageryInfo) e).getImageryCategoryOriginalString(); 1266 } 1267 return null; 1268 } 1269 1143 1270 static String getLogoImage(Object e) { 1144 if (e instanceof ImageryInfo) return e.getAttributionImageRaw() 1145 return null 1146 } 1271 if (e instanceof ImageryInfo) return ((ImageryInfo) e).getAttributionImageRaw(); 1272 return null; 1273 } 1274 1147 1275 static String getLogoUrl(Object e) { 1148 if (e instanceof ImageryInfo) return e.getAttributionImageURL() 1149 return null 1150 } 1276 if (e instanceof ImageryInfo) return ((ImageryInfo) e).getAttributionImageURL(); 1277 return null; 1278 } 1279 1151 1280 static String getPermissionReferenceUrl(Object e) { 1152 if (e instanceof ImageryInfo) return e.getPermissionReferenceURL() 1153 return e.get("properties").getString("license_url", null) 1154 } 1281 if (e instanceof ImageryInfo) return ((ImageryInfo) e).getPermissionReferenceURL(); 1282 return ((Map<String, JsonObject>) e).get("properties").getString("license_url", null); 1283 } 1284 1155 1285 static Map<String,String> getDescriptions(Object e) { 1156 Map<String,String> res = new HashMap<String, String>() 1286 Map<String,String> res = new HashMap<String, String>(); 1157 1287 if (e instanceof ImageryInfo) { 1158 String a = e.getDescription()1159 if (a ) res.put("en", a)1288 String a = ((ImageryInfo) e).getDescription(); 1289 if (a != null) res.put("en", a); 1160 1290 } else { 1161 String a = e.get("properties").getString("description", null) 1162 if (a) res.put("en", a.replaceAll("''","'")) 1163 } 1164 return res 1165 } 1166 static Boolean getValidGeoreference(Object e) { 1167 if (e instanceof ImageryInfo) return e.isGeoreferenceValid() 1168 return false 1169 } 1170 static Boolean getDefault(Object e) { 1171 if (e instanceof ImageryInfo) return e.isDefaultEntry() 1172 return e.get("properties").getBoolean("default", false) 1173 } 1291 String a = ((Map<String, JsonObject>) e).get("properties").getString("description", null); 1292 if (a != null) res.put("en", a.replaceAll("''","'")); 1293 } 1294 return res; 1295 } 1296 1297 static boolean getValidGeoreference(Object e) { 1298 if (e instanceof ImageryInfo) return ((ImageryInfo) e).isGeoreferenceValid(); 1299 return false; 1300 } 1301 1302 static boolean getDefault(Object e) { 1303 if (e instanceof ImageryInfo) return ((ImageryInfo) e).isDefaultEntry(); 1304 return ((Map<String, JsonObject>) e).get("properties").getBoolean("default", false); 1305 } 1306 1174 1307 String getDescription(Object o) { 1175 def url = getUrl(o)1176 def cc = getCountryCode(o)1308 String url = getUrl(o); 1309 String cc = getCountryCode(o); 1177 1310 if (cc == null) { 1178 def j = josmUrls.get(url)1179 if (j != null) cc = getCountryCode(j) 1311 ImageryInfo j = josmUrls.get(url); 1312 if (j != null) cc = getCountryCode(j); 1180 1313 if (cc == null) { 1181 def e = eliUrls.get(url)1182 if (e != null) cc = getCountryCode(e) 1314 JsonObject e = eliUrls.get(url); 1315 if (e != null) cc = getCountryCode(e); 1183 1316 } 1184 1317 } 1185 1318 if (cc == null) { 1186 cc = ''1319 cc = ""; 1187 1320 } else { 1188 cc = "[ $cc] "1189 } 1190 def d = cc + getName(o) + " - " + getUrl(o)1191 if (option s.shorten) {1192 def MAXLEN = 1401193 if (d.length() > MAXLEN) d = d.substring(0, MAXLEN-1) + "..." 1194 } 1195 return d 1321 cc = "["+cc+"] "; 1322 } 1323 String d = cc + getName(o) + " - " + getUrl(o); 1324 if (optionShorten) { 1325 final int MAXLEN = 140; 1326 if (d.length() > MAXLEN) d = d.substring(0, MAXLEN-1) + "..."; 1327 } 1328 return d; 1196 1329 } 1197 1330 }
Note:
See TracChangeset
for help on using the changeset viewer.