Changeset 7553 in josm for trunk/taginfoextract.groovy


Ignore:
Timestamp:
2014-09-17T22:27:53+02:00 (10 years ago)
Author:
bastiK
Message:

see #10512 - better taginfo support

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/taginfoextract.groovy

    r7544 r7553  
    99
    1010import java.io.BufferedReader
    11 import java.util.ArrayList
     11//import java.util.ArrayList
     12import java.awt.image.BufferedImage
     13import javax.imageio.ImageIO
    1214
    1315import org.openstreetmap.josm.Main
    1416import org.openstreetmap.josm.data.coor.LatLon
    1517import org.openstreetmap.josm.data.osm.Node
     18import org.openstreetmap.josm.data.osm.Way
    1619import org.openstreetmap.josm.data.projection.Projections
    1720import org.openstreetmap.josm.data.Version
     21import org.openstreetmap.josm.gui.mappaint.AreaElemStyle
    1822import org.openstreetmap.josm.gui.mappaint.Cascade
    1923import org.openstreetmap.josm.gui.mappaint.Environment
     24import org.openstreetmap.josm.gui.mappaint.LineElemStyle
    2025import org.openstreetmap.josm.gui.mappaint.mapcss.Condition.SimpleKeyValueCondition
    2126import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSStyleSource
     
    2631import org.openstreetmap.josm.io.CachedFile
    2732
    28 basedir = "."
    29 
    30 def cli = new CliBuilder(usage:'taginfoextract.groovy [options] [inputfile]',
    31     header:"Options:",
    32     footer:"[inputfile]  the file to process (optional, default is 'resource://styles/standard/elemstyles.mapcss')")
    33 cli.o(args:1, argName: "file", "output file, - prints to stdout (default: -)")
    34 cli._(longOpt:'svnrev', args:1, argName:"revision", "corresponding revision of the repository http://svn.openstreetmap.org/ (optional, current revision is fetched from the web if not given)")
    35 cli.h(longOpt:'help', "show this help")
    36 options = cli.parse(args)
    37 
    38 if (options.h) {
    39     cli.usage()
    40     System.exit(0)
     33import org.openstreetmap.josm.gui.NavigatableComponent
     34import org.openstreetmap.josm.data.osm.visitor.paint.StyledMapRenderer
     35import org.openstreetmap.josm.data.Bounds
     36//import org.openstreetmap.josm.data.osm.DataSet
     37import org.openstreetmap.josm.data.osm.visitor.paint.MapPaintSettings
     38
     39class taginfoextract {
     40   
     41    static def options
     42    static String image_dir
     43    int josm_svn_revision
     44    String input_file
     45    MapCSSStyleSource style_source
     46    FileWriter output_file
     47    def base_dir = "."
     48    def tags = [] as Set
     49   
     50    private def cached_svnrev
     51
     52    /**
     53     * Check if a certain tag is supported by the style as node / way / area.
     54     */
     55    abstract class Checker {
     56       
     57        def tag
     58        def osm
     59       
     60        Checker(tag) {
     61            this.tag = tag
     62        }
     63       
     64        def apply_stylesheet(osm) {
     65            osm.put(tag[0], tag[1])
     66            def mc = new MultiCascade()
     67           
     68            def env = new Environment(osm, mc, null, style_source)
     69            for (def r in style_source.rules) {
     70                env.clearSelectorMatchingInformation()
     71                env.layer = r.selector.getSubpart()
     72                if (r.selector.matches(env)) {
     73                    // ignore selector range
     74                    if (env.layer == null) {
     75                        env.layer = "default"
     76                    }
     77                    r.execute(env)
     78                }
     79            }
     80            env.layer = "default"
     81            return env
     82        }
     83       
     84        /**
     85         * Determine full image url (can refer to JOSM or OSM repository).
     86         */
     87        def find_image_url(path) {
     88            def f = new File("${base_dir}/images/styles/standard/${path}")
     89            if (f.exists()) {
     90                def rev = osm_svn_revision()
     91                return "http://trac.openstreetmap.org/export/${rev}/subversion/applications/share/map-icons/classic.small/${path}"
     92            }
     93            f = new File("${base_dir}/images/${path}")
     94            if (f.exists()) {
     95                return "https://josm.openstreetmap.de/export/${josm_svn_revision}/josm/trunk/images/${path}"
     96            }
     97            assert false, "Cannot find image url for ${path}"
     98        }
     99
     100        /**
     101         * Create image file from ElemStyle.
     102         * @return the URL
     103         */       
     104        def create_image(elem_style, type, nc) {
     105            def img = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB)
     106            def g = img.createGraphics()
     107            g.setClip(0, 0, 16, 16)
     108            def renderer = new StyledMapRenderer(g, nc, false)
     109            renderer.getSettings(false)
     110            elem_style.paintPrimitive(osm, MapPaintSettings.INSTANCE, renderer, false, false)
     111            def image_url = "${image_dir}/${type}_${tag[0]}=${tag[1]}.png"
     112            ImageIO.write(img, "png", new File(image_url))
     113            return image_url
     114        }
     115
     116        /**
     117         * Checks, if tag is supported and find URL for image icon in this case.
     118         * @param generate_image if true, create or find a suitable image icon and return URL,
     119         * if false, just check if tag is supported and return true or false
     120         */
     121        abstract def find_url(boolean generate_image)
     122    }
     123
     124    class NodeChecker extends Checker {
     125        NodeChecker(tag) {
     126            super(tag)
     127        }
     128
     129        def find_url(boolean generate_image) {
     130            osm = new Node(new LatLon(0,0))
     131            def env = apply_stylesheet(osm)
     132            def c = env.mc.getCascade("default")
     133            def image = c.get("icon-image")
     134            if (image) {
     135                if (image instanceof IconReference) {
     136                    if (image.iconName != "misc/deprecated.png")
     137                        return find_image_url(image.iconName)
     138                }
     139            }
     140        }
     141    }
     142
     143    class WayChecker extends Checker {
     144        WayChecker(tag) {
     145            super(tag)
     146        }
     147
     148        def find_url(boolean generate_image) {
     149            osm = new Way()
     150            def nc = new NavigatableComponent()
     151            def n1 = new Node(nc.getLatLon(2,8))
     152            def n2 = new Node(nc.getLatLon(14,8))
     153            osm.addNode(n1)
     154            osm.addNode(n2)
     155            def env = apply_stylesheet(osm)
     156            def les = LineElemStyle.createLine(env)
     157            if (les != null) {
     158                if (!generate_image) return true
     159                return create_image(les, 'way', nc)
     160            }
     161        }
     162    }
     163
     164    class AreaChecker extends Checker {
     165        AreaChecker(tag) {
     166            super(tag)
     167        }
     168
     169        def find_url(boolean generate_image) {
     170            osm = new Way()
     171            def nc = new NavigatableComponent()
     172            def n1 = new Node(nc.getLatLon(2,2))
     173            def n2 = new Node(nc.getLatLon(14,2))
     174            def n3 = new Node(nc.getLatLon(14,14))
     175            def n4 = new Node(nc.getLatLon(2,14))
     176            osm.addNode(n1)
     177            osm.addNode(n2)
     178            osm.addNode(n3)
     179            osm.addNode(n4)
     180            osm.addNode(n1)
     181            def env = apply_stylesheet(osm)
     182            def aes = AreaElemStyle.create(env)
     183            if (aes != null) {
     184                if (!generate_image) return true
     185                return create_image(aes, 'area', nc)
     186            }
     187        }
     188    }
     189
     190    /**
     191     * Main method.
     192     */
     193    static main(def args) {
     194        parse_command_line_arguments(args)
     195        def script = new taginfoextract()
     196        script.run()
     197        System.exit(0)
     198    }
     199
     200    /**
     201     * Parse command line arguments.
     202     */
     203    static void parse_command_line_arguments(args) {
     204        def cli = new CliBuilder(usage:'taginfoextract.groovy [options] [inputfile]',
     205            header:"Options:",
     206            footer:"[inputfile]  the file to process (optional, default is 'resource://styles/standard/elemstyles.mapcss')")
     207        cli.o(args:1, argName: "file", "output file, - prints to stdout (default: -)")
     208        cli._(longOpt:'svnrev', args:1, argName:"revision", "corresponding revision of the repository http://svn.openstreetmap.org/ (optional, current revision is fetched from the web if not given)")
     209        cli._(longOpt:'imgdir', args:1, argName:"directory", "directory to put the generated images in (default: ./taginfo-img)")
     210        cli._(longOpt:'svnweb', 'fetch revision of the repository http://svn.openstreetmap.org/ from web and not from the local repository')
     211        cli.h(longOpt:'help', "show this help")
     212        options = cli.parse(args)
     213
     214        if (options.h) {
     215            cli.usage()
     216            System.exit(0)
     217        }
     218        if (options.arguments().size() > 1) {
     219            System.err.println "Error: More than one input file given!"
     220            cli.usage()
     221            System.exit(-1)
     222        }
     223        if (options.svnrev) {
     224            assert Integer.parseInt(options.svnrev) > 0
     225        }
     226        image_dir = 'taginfo-img'
     227        if (options.imgdir) {
     228            image_dir = options.imgdir
     229        }
     230        def image_dir_file = new File(image_dir)
     231        if (!image_dir_file.exists()) {
     232            image_dir_file.mkdirs()
     233        }
     234    }
     235   
     236    void run() {
     237        init()
     238        parse_style_sheet()
     239        collect_tags()
     240
     241        def datetime = new Date().format("yyyyMMdd'T'hhmmssZ")
     242        output """{
     243                |  "data_format": 1,
     244                |  "data_updated": "${datetime}",
     245                |  "project": {
     246                |    "name": "JOSM main mappaint style",
     247                |    "description": "Tags supported by the main mappaint style in the OSM editor JOSM",
     248                |    "project_url": "http://josm.openstreetmap.de/",
     249                |    "icon_url": "http://josm.openstreetmap.de/export/7543/josm/trunk/images/logo_16x16x8.png",
     250                |    "contact_name": "JOSM developer team",
     251                |    "contact_email": "josm-dev@openstreetmap.org"
     252                |  },
     253                |  "tags": [
     254                |""".stripMargin()
     255        // another optional field is "data_url": ...
     256
     257        def sep = ""
     258        for (tag in tags) {
     259            def types = []
     260            def final_url = null
     261
     262            def node_url = new NodeChecker(tag).find_url(true)
     263            if (node_url) {
     264                types += '"node"'
     265                final_url = node_url
     266            }
     267            def way_url = new WayChecker(tag).find_url(final_url == null)
     268            if (way_url) {
     269                types += '"way"'
     270                if (!final_url) {
     271                    final_url = way_url
     272                }
     273            }
     274            def area_url = new AreaChecker(tag).find_url(final_url == null)
     275            if (area_url) {
     276                types += '"area"'
     277                if (!final_url) {
     278                    final_url = area_url
     279                }
     280            }
     281           
     282            output """${sep}    {
     283                     |      "key": "${tag[0]}",
     284                     |      "value": "${tag[1]}",
     285                     |      "object_types": ${types}""".stripMargin()
     286            if (final_url != null) {
     287                output """,
     288                     |      "icon_url": "${final_url}"
     289                     |    }""".stripMargin()
     290            } else {
     291                output """
     292                     |    }""".stripMargin()
     293            }
     294            sep = ",\n"
     295        }   
     296        output """
     297        |  ]
     298        |}
     299        |""".stripMargin()
     300
     301        if (output_file != null) {
     302            output_file.close()
     303        }
     304    }
     305
     306    /**
     307     * Initialize the script.
     308     */
     309    def init() {
     310        Main.initApplicationPreferences()
     311        Main.pref.enableSaveOnPut(false)
     312        Main.setProjection(Projections.getProjectionByCode("EPSG:3857"))
     313
     314        josm_svn_revision = Version.getInstance().getVersion()
     315        assert josm_svn_revision != Version.JOSM_UNKNOWN_VERSION
     316
     317        if (options.arguments().size() == 0) {
     318            input_file = "resource://styles/standard/elemstyles.mapcss"
     319        } else {
     320            input_file = options.arguments()[0]
     321        }
     322
     323        output_file = null
     324        if (options.o && options.o != "-") {
     325            output_file = new FileWriter(options.o)
     326        }
     327    }
     328
     329    /**
     330     * Get revision for the repository http://svn.openstreetmap.org.
     331     */
     332    def osm_svn_revision() {
     333        if (cached_svnrev != null) return cached_svnrev
     334        if (options.svnrev) {
     335            cached_svnrev = Integer.parseInt(options.svnrev)
     336            return cached_svnrev
     337        }
     338        def xml
     339        if (options.svnweb) {
     340            xml = "svn info --xml http://svn.openstreetmap.org/applications/share/map-icons/classic.small".execute().text
     341        } else {
     342            xml = "svn info --xml ${base_dir}/images/styles/standard/".execute().text
     343        }
     344       
     345        def svninfo = new XmlParser().parseText(xml)
     346        def rev = svninfo.entry.'@revision'[0]
     347        cached_svnrev = Integer.parseInt(rev)
     348        assert cached_svnrev > 0
     349        return cached_svnrev
     350    }
     351   
     352    /**
     353     * Read the style sheet file and parse the MapCSS code.
     354     */
     355    def parse_style_sheet() {
     356        def file = new CachedFile(input_file)
     357        def stream = file.getInputStream()
     358        def parser = new MapCSSParser(stream, "UTF-8", MapCSSParser.LexicalState.DEFAULT)
     359        style_source = new MapCSSStyleSource("")
     360        style_source.url = ""
     361        parser.sheet(style_source)
     362    }
     363   
     364    /**
     365     * Collect all the tag from the style sheet.
     366     */
     367    def collect_tags() {
     368        for (rule in style_source.rules) {
     369            def selector = rule.selector
     370            if (selector instanceof GeneralSelector) {
     371                def conditions = selector.getConditions()
     372                for (cond in conditions) {
     373                    if (cond instanceof SimpleKeyValueCondition) {
     374                        tags.add([cond.k, cond.v])
     375                    }
     376                }
     377            }
     378        }
     379    }
     380
     381    /**
     382     * Write the JSON output (either to file or to command line).
     383     */   
     384    def output(x) {
     385        if (output_file != null) {
     386            output_file.write(x)
     387        } else {
     388            print x
     389        }
     390    }
     391
     392    static def err_println(s) {
     393        System.err.println(s);
     394    }
     395
     396    static def err_print(s) {
     397        System.err.print(s);
     398    }
     399   
    41400}
    42 if (options.arguments().size() > 1) {
    43     System.err.println "Error: More than one input file given!"
    44     cli.usage()
    45     System.exit(-1)
    46 }
    47 if (options.svnrev) {
    48     assert Integer.parseInt(options.svnrev) > 0
    49 }
    50 
    51 Main.initApplicationPreferences()
    52 Main.pref.enableSaveOnPut(false)
    53 Main.setProjection(Projections.getProjectionByCode("EPSG:3857"))
    54 
    55 josm_svn_revsion = Version.getInstance().getVersion()
    56 assert josm_svn_revsion != Version.JOSM_UNKNOWN_VERSION
    57 
    58 cached_svnrev = null
    59 /**
    60  * Get revision for the repository http://svn.openstreetmap.org.
    61  */
    62 def osm_svn_revision() {
    63     if (cached_svnrev != null) return cached_svnrev
    64     if (options.svnrev) {
    65         cached_svnrev = Integer.parseInt(options.svnrev)
    66         return cached_svnrev
    67     }
    68     //xml = "svn info --xml http://svn.openstreetmap.org/applications/share/map-icons/classic.small".execute().text
    69     xml = ("svn info --xml ${basedir}/images/styles/standard/").execute().text
    70        
    71         def svninfo = new XmlParser().parseText(xml)
    72         def rev = svninfo.entry.'@revision'[0]
    73         cached_svnrev = Integer.parseInt(rev)
    74         assert cached_svnrev > 0
    75         return cached_svnrev
    76 }
    77 
    78 /**
    79  * Determine full image url (can refer to JOSM or OSM repository).
    80  */
    81 def find_image_url(path) {
    82     def f = new File("${basedir}/images/styles/standard/${path}")
    83     if (f.exists()) {
    84         def rev = osm_svn_revision()
    85         return "http://trac.openstreetmap.org/export/${rev}/subversion/applications/share/map-icons/classic.small/${path}"
    86     }
    87     f = new File("${basedir}/images/${path}")
    88     if (f.exists()) {
    89         return "https://josm.openstreetmap.de/export/${josm_svn_revsion}/josm/trunk/images/${path}"
    90     }
    91     assert false, "Cannot find image url for ${path}"
    92 }
    93 
    94 def input_file
    95 if (options.arguments().size() == 0) {
    96     input_file = "resource://styles/standard/elemstyles.mapcss"
    97 } else {
    98     input_file = options.arguments()[0]
    99 }
    100 
    101 
    102 def file = new CachedFile(input_file)
    103 def stream = file.getInputStream()
    104 def parser = new MapCSSParser(stream, "UTF-8", MapCSSParser.LexicalState.DEFAULT)
    105 def style_source = new MapCSSStyleSource("")
    106 style_source.url = ""
    107 parser.sheet(style_source)
    108 
    109 def tags = [] as Set
    110 
    111 for (rule in style_source.rules) {
    112     def selector = rule.selector
    113     if (selector instanceof GeneralSelector) {
    114         def conditions = selector.getConditions()
    115         for (cond in conditions) {
    116             if (cond instanceof SimpleKeyValueCondition) {
    117                 if (selector.base == "node") {
    118                     tags.add([cond.k, cond.v])
    119                 }
    120             }
    121         }
    122     }
    123 }
    124 
    125 output_file = null
    126 if (options.o && options.o != "-") {
    127     output_file = new FileWriter(options.o)
    128 }
    129 
    130 def output(x) {
    131     if (output_file != null) {
    132         output_file.write(x)
    133     } else {
    134         print x
    135     }
    136 }
    137 
    138 datetime = new Date().format("yyyyMMdd'T'hhmmssZ")
    139 
    140 output """{
    141   "data_format": 1,
    142   "data_url": "FIXME",
    143   "data_updated": "${datetime}",
    144   "project": {
    145     "name": "JOSM main mappaint style",
    146     "description": "Tags supported by the main mappaint style in the OSM editor JOSM",
    147     "project_url": "http://josm.openstreetmap.de/",
    148     "icon_url": "http://josm.openstreetmap.de/export/7543/josm/trunk/images/logo_16x16x8.png",
    149     "contact_name": "JOSM developer team",
    150     "contact_email": "josm-dev@openstreetmap.org"
    151   },
    152   "tags": [
    153 """
    154 
    155 sep = ""
    156 for (tag in tags) {
    157     def k = tag[0]
    158     def v = tag[1]
    159     def osm = new Node(new LatLon(0,0))
    160     osm.put(k, v)
    161     def mc = new MultiCascade()
    162    
    163     def env = new Environment(osm, mc, null, style_source)
    164     for (def r in style_source.rules) {
    165         env.clearSelectorMatchingInformation()
    166         env.layer = r.selector.getSubpart()
    167         if (r.selector.matches(env)) {
    168             // ignore selector range
    169             if (env.layer == null) {
    170                 env.layer = "default"
    171             }
    172             r.execute(env)
    173         }
    174     }
    175     def c = mc.getCascade("default")
    176     def image = c.get("icon-image")
    177     if (image) {
    178         if (!(image instanceof IconReference)) continue
    179         def image_url = find_image_url(image.iconName)
    180 
    181         output """${sep}    {
    182                  |      "key": "${k}",
    183                  |      "value": "${v}",
    184                  |      "object_types": ["node"],
    185                  |      "icon_url": "${image_url}"
    186                  |    }""".stripMargin()
    187     sep = ",\n"
    188     }
    189 }
    190 output """
    191   ]
    192 }
    193 """
    194 
    195 if (output_file != null) {
    196     output_file.close()
    197 }
    198 
    199 System.exit(0)
    200 
     401
Note: See TracChangeset for help on using the changeset viewer.