source: josm/trunk/scripts/SyncEditorLayerIndex.groovy@ 11964

Last change on this file since 11964 was 11964, checked in by stoecker, 7 years ago

add maps sanitity check (will cause new red entries) for double points in bounds, first part for proper formatted XML output in sync script to make copying data easier

  • Property svn:eol-style set to native
File size: 26.2 KB
Line 
1// License: GPL. For details, see LICENSE file.
2/**
3 * Compare and analyse the differences of the editor layer index and the JOSM imagery list.
4 * The goal is to keep both lists in sync.
5 *
6 * The editor layer index project (https://github.com/osmlab/editor-layer-index)
7 * provides also a version in the JOSM format, but the GEOJSON is the original source
8 * format, so we read that.
9 *
10 * How to run:
11 * -----------
12 *
13 * Main JOSM binary needs to be in classpath, e.g.
14 *
15 * $ groovy -cp ../dist/josm-custom.jar SyncEditorLayerIndex.groovy
16 *
17 * Add option "-h" to show the available command line flags.
18 */
19import javax.json.Json
20import javax.json.JsonArray
21import javax.json.JsonObject
22import javax.json.JsonReader
23
24import org.openstreetmap.josm.data.imagery.ImageryInfo
25import org.openstreetmap.josm.data.imagery.Shape
26import org.openstreetmap.josm.io.imagery.ImageryReader
27
28class SyncEditorLayerIndex {
29
30 List<ImageryInfo> josmEntries;
31 JsonArray eliEntries;
32
33 def eliUrls = new HashMap<String, JsonObject>()
34 def josmUrls = new HashMap<String, ImageryInfo>()
35 def josmMirrors = new HashMap<String, ImageryInfo>()
36
37 static String eliInputFile = 'imagery.geojson'
38 static String josmInputFile = 'maps.xml'
39 static String ignoreInputFile = 'maps_ignores.txt'
40 static FileWriter outputFile = null
41 static BufferedWriter outputStream = null
42 def skip = [:]
43
44 static def options
45
46 /**
47 * Main method.
48 */
49 static main(def args) {
50 parse_command_line_arguments(args)
51 def script = new SyncEditorLayerIndex()
52 script.loadSkip()
53 script.start()
54 script.loadJosmEntries()
55 if(options.josmxml) {
56 def file = new FileWriter(options.josmxml)
57 def stream = new BufferedWriter(file)
58 script.printentries(script.josmEntries, stream)
59 }
60 script.loadELIEntries()
61 if(options.elixml) {
62 def file = new FileWriter(options.elixml)
63 def stream = new BufferedWriter(file)
64 script.printentries(script.eliEntries, stream)
65 }
66 script.checkInOneButNotTheOther()
67 script.checkCommonEntries()
68 script.end()
69 if(outputStream != null) {
70 outputStream.close();
71 }
72 if(outputFile != null) {
73 outputFile.close();
74 }
75 }
76
77 /**
78 * Parse command line arguments.
79 */
80 static void parse_command_line_arguments(args) {
81 def cli = new CliBuilder(width: 160)
82 cli.o(longOpt:'output', args:1, argName: "output", "Output file, - prints to stdout (default: -)")
83 cli.e(longOpt:'eli_input', args:1, argName:"eli_input", "Input file for the editor layer index (geojson). Default is $eliInputFile (current directory).")
84 cli.j(longOpt:'josm_input', args:1, argName:"josm_input", "Input file for the JOSM imagery list (xml). Default is $josmInputFile (current directory).")
85 cli.i(longOpt:'ignore_input', args:1, argName:"ignore_input", "Input file for the ignore list. Default is $ignoreInputFile (current directory).")
86 cli.s(longOpt:'shorten', "shorten the output, so it is easier to read in a console window")
87 cli.n(longOpt:'noskip', argName:"noskip", "don't skip known entries")
88 cli.x(longOpt:'xhtmlbody', argName:"xhtmlbody", "create XHTML body for display in a web page")
89 cli.X(longOpt:'xhtml', argName:"xhtml", "create XHTML for display in a web page")
90 cli.p(longOpt:'elixml', args:1, argName:"elixml", "ELI entries for use in JOSM as XML file (incomplete)")
91 cli.q(longOpt:'josmxml', args:1, argName:"josmxml", "JOSM entries reoutput as XML file (incomplete)")
92 cli.m(longOpt:'nomissingeli', argName:"nomissingeli", "don't show missing editor layer index entries")
93 cli.h(longOpt:'help', "show this help")
94 options = cli.parse(args)
95
96 if (options.h) {
97 cli.usage()
98 System.exit(0)
99 }
100 if (options.eli_input) {
101 eliInputFile = options.eli_input
102 }
103 if (options.josm_input) {
104 josmInputFile = options.josm_input
105 }
106 if (options.ignore_input) {
107 ignoreInputFile = options.ignore_input
108 }
109 if (options.output && options.output != "-") {
110 outputFile = new FileWriter(options.output)
111 outputStream = new BufferedWriter(outputFile)
112 }
113 }
114
115 void loadSkip() {
116 FileReader fr = new FileReader(ignoreInputFile)
117 def line
118
119 while((line = fr.readLine()) != null) {
120 def res = (line =~ /^\|\| *(ELI|Ignore) *\|\| *\{\{\{(.+)\}\}\} *\|\|/)
121 if(res.count)
122 {
123 if(res[0][1].equals("Ignore")) {
124 skip[res[0][2]] = "green"
125 } else {
126 skip[res[0][2]] = "darkgoldenrod"
127 }
128 }
129 }
130 }
131
132 void myprintlnfinal(String s) {
133 if(outputStream != null) {
134 outputStream.write(s)
135 outputStream.newLine()
136 } else {
137 println s
138 }
139 }
140
141 void myprintln(String s) {
142 if(skip.containsKey(s)) {
143 String color = skip.get(s)
144 skip.remove(s)
145 if(options.xhtmlbody || options.xhtml) {
146 s = "<pre style=\"margin:3px;color:"+color+"\">"+s.replaceAll("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;")+"</pre>"
147 }
148 if (!options.noskip) {
149 return
150 }
151 } else if(options.xhtmlbody || options.xhtml) {
152 String color = s.startsWith("***") ? "black" : ((s.startsWith("+ ") || s.startsWith("+++ ELI")) ? "blue" : "red")
153 s = "<pre style=\"margin:3px;color:"+color+"\">"+s.replaceAll("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;")+"</pre>"
154 }
155 myprintlnfinal(s)
156 }
157
158 void start() {
159 if (options.xhtml) {
160 myprintlnfinal "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"
161 myprintlnfinal "<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"/><title>JOSM - ELI differences</title></head><body>\n"
162 }
163 }
164
165 void end() {
166 for (def s: skip.keySet()) {
167 myprintln "+++ Obsolete skip entry: " + s
168 }
169 if (options.xhtml) {
170 myprintlnfinal "</body></html>\n"
171 }
172 }
173
174 void loadELIEntries() {
175 FileReader fr = new FileReader(eliInputFile)
176 JsonReader jr = Json.createReader(fr)
177 eliEntries = jr.readObject().get("features")
178 jr.close()
179
180 for (def e : eliEntries) {
181 def url = getUrl(e)
182 if (url.contains("{z}")) {
183 myprintln "+++ ELI-URL uses {z} instead of {zoom}: "+url
184 url = url.replace("{z}","{zoom}")
185 }
186 if (eliUrls.containsKey(url)) {
187 myprintln "+++ ELI-URL is not unique: "+url
188 } else {
189 eliUrls.put(url, e)
190 }
191 }
192 myprintln "*** Loaded ${eliEntries.size()} entries (ELI). ***"
193 }
194
195 void printentries(def entries, def stream) {
196 stream.write "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n"
197 stream.write "<imagery xmlns=\"http://josm.openstreetmap.de/maps-1.0\">\n"
198 for (def e : entries) {
199 def best = "eli-best".equals(getQuality(e))
200 stream.write " <entry"+(best ? " eli-best=\"true\"" : "" )+">\n"
201 stream.write " <name>${getName(e)}</name>\n"
202 stream.write " <id>${getId(e)}</id>\n"
203 def minlat = 1000
204 def minlon = 1000
205 def maxlat = -1000
206 def maxlon = -1000
207 def shapes = ""
208 def sep = "\n "
209 for(def s: getShapes(e)) {
210 shapes += " <shape>"
211 def i = 0
212 for(def p: s.getPoints()) {
213 def lat = p.getLat()
214 def lon = p.getLon()
215 if(lat > maxlat) maxlat = lat
216 if(lon > maxlon) maxlon = lon
217 if(lat < minlat) minlat = lat
218 if(lon < minlon) minlon = lon
219 if(!(i++%3)) {
220 shapes += sep + " "
221 }
222 shapes += "<point lat='${String.format(Locale.ROOT, "%.7f",lat)}' lon='${String.format(Locale.ROOT, "%.7f",lon)}'/>"
223 }
224 shapes += sep + "</shape>\n"
225 }
226 if(shapes) {
227 stream.write " <bounds min-lat='${minlat}' min-lon='${minlon}' max-lat='${maxlat}' max-lon='${maxlon}'>\n"
228 stream.write shapes + " </bounds>\n"
229 stream.write " </entry>\n"
230 }
231 }
232 stream.write "</imagery>\n"
233 stream.close()
234 }
235
236 void loadJosmEntries() {
237 def reader = new ImageryReader(josmInputFile)
238 josmEntries = reader.parse()
239
240 for (def e : josmEntries) {
241 def url = getUrl(e)
242 if (url.contains("{z}")) {
243 myprintln "+++ JOSM-URL uses {z} instead of {zoom}: "+url
244 url = url.replace("{z}","{zoom}")
245 }
246 if (josmUrls.containsKey(url)) {
247 myprintln "+++ JOSM-URL is not unique: "+url
248 } else {
249 josmUrls.put(url, e)
250 }
251 for (def m : e.getMirrors()) {
252 url = getUrl(m)
253 m.origName = m.getOriginalName().replaceAll(" mirror server( \\d+)?","")
254 if (josmUrls.containsKey(url)) {
255 myprintln "+++ JOSM-Mirror-URL is not unique: "+url
256 } else {
257 josmUrls.put(url, m)
258 josmMirrors.put(url, m)
259 }
260 }
261 }
262 myprintln "*** Loaded ${josmEntries.size()} entries (JOSM). ***"
263 }
264
265 List inOneButNotTheOther(Map m1, Map m2) {
266 def l = []
267 for (def url : m1.keySet()) {
268 if (!m2.containsKey(url)) {
269 def name = getName(m1.get(url))
270 l += " "+getDescription(m1.get(url))
271 }
272 }
273 l.sort()
274 }
275
276 void checkInOneButNotTheOther() {
277 def l1 = inOneButNotTheOther(eliUrls, josmUrls)
278 myprintln "*** URLs found in ELI but not in JOSM (${l1.size()}): ***"
279 if (!l1.isEmpty()) {
280 for (def l : l1) {
281 myprintln "-" + l
282 }
283 }
284
285 if (options.nomissingeli)
286 return
287 def l2 = inOneButNotTheOther(josmUrls, eliUrls)
288 myprintln "*** URLs found in JOSM but not in ELI (${l2.size()}): ***"
289 if (!l2.isEmpty()) {
290 for (def l : l2) {
291 myprintln "+" + l
292 }
293 }
294 }
295
296 void checkCommonEntries() {
297 myprintln "*** Same URL, but different name: ***"
298 for (def url : eliUrls.keySet()) {
299 def e = eliUrls.get(url)
300 if (!josmUrls.containsKey(url)) continue
301 def j = josmUrls.get(url)
302 def ename = getName(e).replace("'","’")
303 def jname = getName(j).replace("'","’")
304 if (!ename.equals(jname)) {
305 myprintln "* Name differs ('${getName(e)}' != '${getName(j)}'): $url"
306 }
307 }
308
309 myprintln "*** Same URL, but different type: ***"
310 for (def url : eliUrls.keySet()) {
311 def e = eliUrls.get(url)
312 if (!josmUrls.containsKey(url)) continue
313 def j = josmUrls.get(url)
314 if (!getType(e).equals(getType(j))) {
315 myprintln "* Type differs (${getType(e)} != ${getType(j)}): ${getName(j)} - $url"
316 }
317 }
318
319 myprintln "*** Same URL, but different zoom bounds: ***"
320 for (def url : eliUrls.keySet()) {
321 def e = eliUrls.get(url)
322 if (!josmUrls.containsKey(url)) continue
323 def j = josmUrls.get(url)
324
325 Integer eMinZoom = getMinZoom(e)
326 Integer jMinZoom = getMinZoom(j)
327 if (eMinZoom != jMinZoom && !(eMinZoom == 0 && jMinZoom == null)) {
328 myprintln "* Minzoom differs (${eMinZoom} != ${jMinZoom}): ${getDescription(j)}"
329 }
330 Integer eMaxZoom = getMaxZoom(e)
331 Integer jMaxZoom = getMaxZoom(j)
332 if (eMaxZoom != jMaxZoom) {
333 myprintln "* Maxzoom differs (${eMaxZoom} != ${jMaxZoom}): ${getDescription(j)}"
334 }
335 }
336
337 myprintln "*** Same URL, but different country code: ***"
338 for (def url : eliUrls.keySet()) {
339 def e = eliUrls.get(url)
340 if (!josmUrls.containsKey(url)) continue
341 def j = josmUrls.get(url)
342 if (!getCountryCode(e).equals(getCountryCode(j))) {
343 myprintln "* Country code differs (${getCountryCode(e)} != ${getCountryCode(j)}): ${getDescription(j)}"
344 }
345 }
346 myprintln "*** Same URL, but different quality: ***"
347 for (def url : eliUrls.keySet()) {
348 def e = eliUrls.get(url)
349 if (!josmUrls.containsKey(url)) {
350 def q = getQuality(e)
351 if("eli-best".equals(q)) {
352 myprintln "- Quality best entry not in JOSM for ${getDescription(e)}"
353 }
354 continue
355 }
356 def j = josmUrls.get(url)
357 if (!getQuality(e).equals(getQuality(j))) {
358 myprintln "* Quality differs (${getQuality(e)} != ${getQuality(j)}): ${getDescription(j)}"
359 }
360 }
361 myprintln "*** Same URL, but different dates: ***"
362 for (def url : eliUrls.keySet()) {
363 def ed = getDate(eliUrls.get(url))
364 if (!josmUrls.containsKey(url)) continue
365 def j = josmUrls.get(url)
366 def jd = getDate(j)
367 // The forms 2015;- or -;2015 or 2015;2015 are handled equal to 2015
368 String ef = ed.replaceAll("\\A-;","").replaceAll(";-\\z","").replaceAll("\\A([0-9-]+);\\1\\z","\$1")
369 // ELI has a strange and inconsistent used end_date definition, so we try again with subtraction by one
370 String ed2 = ed
371 def reg = (ed =~ /^(.*;)(\d\d\d\d)(-(\d\d)(-(\d\d))?)?$/)
372 if(reg != null && reg.count == 1) {
373 Calendar cal = Calendar.getInstance()
374 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)
375 cal.add(Calendar.DAY_OF_MONTH, -1)
376 ed2 = reg[0][1] + cal.get(Calendar.YEAR)
377 if (reg[0][4] != null)
378 ed2 += "-" + String.format("%02d", cal.get(Calendar.MONTH)+1)
379 if (reg[0][6] != null)
380 ed2 += "-" + String.format("%02d", cal.get(Calendar.DAY_OF_MONTH))
381 }
382 String ef2 = ed2.replaceAll("\\A-;","").replaceAll(";-\\z","").replaceAll("\\A([0-9-]+);\\1\\z","\$1")
383 if (!ed.equals(jd) && !ef.equals(jd) && !ed2.equals(jd) && !ef2.equals(jd)) {
384 String t = "'${ed}'"
385 if (!ed.equals(ef)) {
386 t += " or '${ef}'"
387 }
388 if (jd.isEmpty()) {
389 myprintln "- Missing JOSM date (${t}): ${getDescription(j)}"
390 } else if (!ed.isEmpty()) {
391 myprintln "* Date differs (${t} != '${jd}'): ${getDescription(j)}"
392 } else if (!options.nomissingeli) {
393 myprintln "+ Missing ELI date ('${jd}'): ${getDescription(j)}"
394 }
395 }
396 }
397 myprintln "*** Mismatching shapes: ***"
398 for (def url : josmUrls.keySet()) {
399 def j = josmUrls.get(url)
400 def num = 1
401 for (def shape : getShapes(j)) {
402 def p = shape.getPoints()
403 if(!p[0].equals(p[p.size()-1])) {
404 myprintln "+++ JOSM shape $num unclosed: ${getDescription(j)}"
405 }
406 for (def nump = 1; nump < p.size(); ++nump) {
407 if (p[nump-1] == p[nump]) {
408 myprintln "+++ JOSM shape $num double point at ${nump-1}: ${getDescription(j)}"
409 }
410 }
411 ++num
412 }
413 }
414 for (def url : eliUrls.keySet()) {
415 def e = eliUrls.get(url)
416 def num = 1
417 def s = getShapes(e)
418 for (def shape : s) {
419 def p = shape.getPoints()
420 if(!p[0].equals(p[p.size()-1]) && !options.nomissingeli) {
421 myprintln "+++ ELI shape $num unclosed: ${getDescription(e)}"
422 }
423 for (def nump = 1; nump < p.size(); ++nump) {
424 if (p[nump-1] == p[nump]) {
425 myprintln "+++ ELI shape $num double point at ${nump-1}: ${getDescription(e)}"
426 }
427 }
428 ++num
429 }
430 if (!josmUrls.containsKey(url)) {
431 continue
432 }
433 def j = josmUrls.get(url)
434 def js = getShapes(j)
435 if(!s.size() && js.size()) {
436 if(!options.nomissingeli) {
437 myprintln "+ No ELI shape: ${getDescription(j)}"
438 }
439 } else if(!js.size() && s.size()) {
440 // don't report boundary like 5 point shapes as difference
441 if (s.size() != 1 || s[0].getPoints().size() != 5) {
442 myprintln "- No JOSM shape: ${getDescription(j)}"
443 }
444 } else if(s.size() != js.size()) {
445 myprintln "* Different number of shapes (${s.size()} != ${js.size()}): ${getDescription(j)}"
446 } else {
447 for(def nums = 0; nums < s.size(); ++nums) {
448 def ep = s[nums].getPoints()
449 def jp = js[nums].getPoints()
450 if(ep.size() != jp.size()) {
451 myprintln "* Different number of points for shape ${nums+1} (${ep.size()} ! = ${jp.size()})): ${getDescription(j)}"
452 } else {
453 for(def nump = 0; nump < ep.size(); ++nump) {
454 def ept = ep[nump]
455 def jpt = jp[nump]
456 if(Math.abs(ept.getLat()-jpt.getLat()) > 0.000001 || Math.abs(ept.getLon()-jpt.getLon()) > 0.000001) {
457 myprintln "* Different coordinate for point ${nump+1} of shape ${nums+1}: ${getDescription(j)}"
458 nump = ep.size()
459 num = s.size()
460 }
461 }
462 }
463 }
464 }
465 }
466 myprintln "*** Mismatching icons: ***"
467 for (def url : eliUrls.keySet()) {
468 def e = eliUrls.get(url)
469 if (!josmUrls.containsKey(url)) {
470 continue
471 }
472 def j = josmUrls.get(url)
473 def ij = getIcon(j)
474 def ie = getIcon(e)
475 if(ij != null && ie == null) {
476 if(!options.nomissingeli) {
477 myprintln "+ No ELI icon: ${getDescription(j)}"
478 }
479 } else if(ij == null && ie != null) {
480 myprintln "- No JOSM icon: ${getDescription(j)}"
481 } else if(!ij.equals(ie)) {
482 myprintln "* Different icons: ${getDescription(j)}"
483 }
484 }
485 myprintln "*** Miscellaneous checks: ***"
486 def josmIds = new HashMap<String, ImageryInfo>()
487 for (def url : josmUrls.keySet()) {
488 def j = josmUrls.get(url)
489 def id = getId(j)
490 if(josmMirrors.containsKey(url)) {
491 continue
492 }
493 if(id == null) {
494 myprintln "* No JOSM-ID: ${getDescription(j)}"
495 } else if(josmIds.containsKey(id)) {
496 myprintln "* JOSM-ID ${id} not unique: ${getDescription(j)}"
497 } else {
498 josmIds.put(id, j)
499 }
500 def d = getDate(j)
501 if(!d.isEmpty()) {
502 def reg = (d =~ /^(-|(\d\d\d\d)(-(\d\d)(-(\d\d))?)?)(;(-|(\d\d\d\d)(-(\d\d)(-(\d\d))?)?))?$/)
503 if(reg == null || reg.count != 1) {
504 myprintln "* JOSM-Date '${d}' is strange: ${getDescription(j)}"
505 } else {
506 try {
507 def first = verifyDate(reg[0][2],reg[0][4],reg[0][6])
508 def second = verifyDate(reg[0][9],reg[0][11],reg[0][13])
509 if(second.compareTo(first) < 0) {
510 myprintln "* JOSM-Date '${d}' is strange (second earlier than first): ${getDescription(j)}"
511 }
512 }
513 catch (Exception e) {
514 myprintln "* JOSM-Date '${d}' is strange (${e.getMessage()}): ${getDescription(j)}"
515 }
516 }
517 }
518 def js = getShapes(j)
519 if(js.size()) {
520 def minlat = 1000
521 def minlon = 1000
522 def maxlat = -1000
523 def maxlon = -1000
524 for(def s: js) {
525 for(def p: s.getPoints()) {
526 def lat = p.getLat()
527 def lon = p.getLon()
528 if(lat > maxlat) maxlat = lat
529 if(lon > maxlon) maxlon = lon
530 if(lat < minlat) minlat = lat
531 if(lon < minlon) minlon = lon
532 }
533 }
534 def b = j.getBounds()
535 if(b.getMinLat() != minlat || b.getMinLon() != minlon || b.getMaxLat() != maxlat || b.getMaxLon() != maxlon) {
536 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)}"
537 }
538 }
539 }
540 }
541
542 /**
543 * Utility functions that allow uniform access for both ImageryInfo and JsonObject.
544 */
545 static String getUrl(Object e) {
546 if (e instanceof ImageryInfo) return e.url
547 return e.get("properties").getString("url")
548 }
549 static String getDate(Object e) {
550 if (e instanceof ImageryInfo) return e.date ? e.date : ""
551 def p = e.get("properties")
552 def start = p.containsKey("start_date") ? p.getString("start_date") : ""
553 def end = p.containsKey("end_date") ? p.getString("end_date") : ""
554 if(!start.isEmpty() && !end.isEmpty())
555 return start+";"+end
556 else if(!start.isEmpty())
557 return start+";-"
558 else if(!end.isEmpty())
559 return "-;"+end
560 return ""
561 }
562 static Date verifyDate(String year, String month, String day) {
563 def date
564 if(year == null) {
565 date = "3000-01-01"
566 } else {
567 date = year + "-" + (month == null ? "01" : month) + "-" + (day == null ? "01" : day)
568 }
569 def df = new java.text.SimpleDateFormat("yyyy-MM-dd")
570 df.setLenient(false)
571 return df.parse(date)
572 }
573 static String getId(Object e) {
574 if (e instanceof ImageryInfo) return e.getId()
575 return e.get("properties").getString("id")
576 }
577 static String getName(Object e) {
578 if (e instanceof ImageryInfo) return e.getOriginalName()
579 return e.get("properties").getString("name")
580 }
581 static List<Shape> getShapes(Object e) {
582 if (e instanceof ImageryInfo) {
583 def bounds = e.getBounds()
584 if(bounds != null) {
585 return bounds.getShapes()
586 }
587 return []
588 }
589 if(!e.isNull("geometry")) {
590 def ex = e.get("geometry")
591 if(ex != null && !ex.isNull("coordinates")) {
592 def poly = ex.get("coordinates")
593 List<Shape> l = []
594 for(def shapes: poly) {
595 def s = new Shape()
596 for(def point: shapes) {
597 def lon = point[0].toString()
598 def lat = point[1].toString()
599 s.addPoint(lat, lon)
600 }
601 l.add(s)
602 }
603 return l
604 }
605 }
606 return []
607 }
608 static String getType(Object e) {
609 if (e instanceof ImageryInfo) return e.getImageryType().getTypeString()
610 return e.get("properties").getString("type")
611 }
612 static Integer getMinZoom(Object e) {
613 if (e instanceof ImageryInfo) {
614 int mz = e.getMinZoom()
615 return mz == 0 ? null : mz
616 } else {
617 def num = e.get("properties").getJsonNumber("min_zoom")
618 if (num == null) return null
619 return num.intValue()
620 }
621 }
622 static Integer getMaxZoom(Object e) {
623 if (e instanceof ImageryInfo) {
624 int mz = e.getMaxZoom()
625 return mz == 0 ? null : mz
626 } else {
627 def num = e.get("properties").getJsonNumber("max_zoom")
628 if (num == null) return null
629 return num.intValue()
630 }
631 }
632 static String getCountryCode(Object e) {
633 if (e instanceof ImageryInfo) return "".equals(e.getCountryCode()) ? null : e.getCountryCode()
634 return e.get("properties").getString("country_code", null)
635 }
636 static String getQuality(Object e) {
637 if (e instanceof ImageryInfo) return e.isBestMarked() ? "eli-best" : null
638 return (e.get("properties").containsKey("best")
639 && e.get("properties").getBoolean("best")) ? "eli-best" : null
640 }
641 static String getIcon(Object e) {
642 if (e instanceof ImageryInfo) return e.getIcon()
643 return e.get("properties").getString("icon", null)
644 }
645 String getDescription(Object o) {
646 def url = getUrl(o)
647 def cc = getCountryCode(o)
648 if (cc == null) {
649 def j = josmUrls.get(url)
650 if (j != null) cc = getCountryCode(j)
651 if (cc == null) {
652 def e = eliUrls.get(url)
653 if (e != null) cc = getCountryCode(e)
654 }
655 }
656 if (cc == null) {
657 cc = ''
658 } else {
659 cc = "[$cc] "
660 }
661 def d = cc + getName(o) + " - " + getUrl(o)
662 if (options.shorten) {
663 def MAXLEN = 140
664 if (d.length() > MAXLEN) d = d.substring(0, MAXLEN-1) + "..."
665 }
666 return d
667 }
668}
Note: See TracBrowser for help on using the repository browser.