osmlinzaddr.py 4.58 KB
Newer Older
Eliot Blennerhassett's avatar
Eliot Blennerhassett committed
1

2
""" OSM LINZ Address
3
Usage: my_program.py [-h -o DIRECTORY --min-nodes=COUNT --max-nodes=COUNT --include-location=LEVEL] [-d DATABASE]
4 5 6 7

Options:
  -d DATABASE --database DATABASE  spatialite database containing linz_addr table [default: osmlinzaddr.sqlite]
  -h --help    show this
8
  -o DIRECTORY --output=DIRECTORY   Specify output directory. [default: linz_places]
9 10
  --min-nodes=COUNT  Minimum number of nodes per output file. [default: 1]
  --max-nodes=COUNT  Maximum number of nodes per output file. [default: 8000]
11
  --include-location=LEVEL  1:Include suburb/hamlet 2: and city tags in output. [default: 1]
12
"""
Eliot Blennerhassett's avatar
Eliot Blennerhassett committed
13

14
from __future__ import print_function, division, unicode_literals
Eliot Blennerhassett's avatar
Eliot Blennerhassett committed
15
from lxml import etree as ET
16
from docopt import docopt
17

Eliot Blennerhassett's avatar
Eliot Blennerhassett committed
18
import os
19
import sqlite3.dbapi2 as db
Eliot Blennerhassett's avatar
Eliot Blennerhassett committed
20 21


22 23 24 25
def add_tag(node, k, v):
    ET.SubElement(node, "tag", k=k, v=v)


Eliot Blennerhassett's avatar
Eliot Blennerhassett committed
26
def generate_osmchange(dbfile, outdir,
27 28 29
            changeset=1,
            min_nodes=1, max_nodes=8000,
            include_location=False):
Eliot Blennerhassett's avatar
Eliot Blennerhassett committed
30 31 32 33 34 35 36

    try:
        os.makedirs(outdir)
    except OSError:
        pass

    con = db.connect(dbfile)
37 38 39
    con.enable_load_extension(True)
    con.execute("SELECT load_extension('mod_spatialite')")

Eliot Blennerhassett's avatar
Eliot Blennerhassett committed
40 41
    cur = con.cursor()

42 43 44
    # Select subsets by place
    q = 'select * from places'
    places = list(cur.execute(q))
Eliot Blennerhassett's avatar
Eliot Blennerhassett committed
45

46 47 48
    with open(outdir + '/file_list.csv', 'w') as f:
        f.write('place, num_addresses, uploader, date\n')

49 50 51
    for place in places:
        generate_osmchange_place(place, cur, outdir,
            changeset, include_location)
Eliot Blennerhassett's avatar
Eliot Blennerhassett committed
52 53


54
def generate_josm_tags_place(place, fn, outdir='.', source_rev='66'):
55 56 57 58 59 60 61 62 63 64
    tags = []
    tags.append('created_by=https://git.nzoss.org.nz/ewblen/osmlinzaddr/blob/master/osmlinzaddr.py')
    tags.append('attribution=https://wiki.openstreetmap.org/wiki/Contributors#LINZ')
    tags.append('source=https://data.linz.govt.nz/layer/3353-nz-street-address')
    tags.append('source:revision=%s' % source_rev)
    tags.append('comment=LINZ address import %s' % fn)
    tags.append('')
    path = outdir + "/%s.changeset_tags" % fn
    with open(path, 'w') as f:
        f.write('\n'.join(tags))
Eliot Blennerhassett's avatar
Eliot Blennerhassett committed
65 66


67
def generate_osmchange_place(place, dbcursor, outdir,
68
                            changeset, include_location):
Eliot Blennerhassett's avatar
Eliot Blennerhassett committed
69

70
    if place[0] is None:
71
        q = '''select linz_id, housenumber, street, x, y from linz_not_osm
72
        where city is NULL and suburb="{1}"
73 74
        '''.format(*(place))
    else:
75
        q = '''select linz_id, housenumber, street, x, y from linz_not_osm
76
        where city="{0}" and suburb="{1}"
77
        '''.format(*(place))
Eliot Blennerhassett's avatar
Eliot Blennerhassett committed
78

79
    rows = dbcursor.execute(q)
80

81
    lrows = list(rows)
Eliot Blennerhassett's avatar
Eliot Blennerhassett committed
82

83
    city, suburb = place[0:2]
Eliot Blennerhassett's avatar
Eliot Blennerhassett committed
84

85
    if city is None:
86 87 88 89 90
        fn = suburb
    else:
        fn = city + '-' + suburb
    fn = fn.replace(' ', '_')
    fn = fn.replace('/', '_')
Eliot Blennerhassett's avatar
Eliot Blennerhassett committed
91

92 93 94 95 96 97 98 99
    with open(outdir + '/file_list.csv', 'a') as f:
        f.write('%s,%d\n' % (fn, len(lrows)))
    # keep track of empty (complete) places too

    if not len(lrows):
        print("No addresses in %s!?" % str(place))
        return

100
    path = outdir + "/%s.osc" % fn
101
    print("%s : %d nodes" % (fn, len(lrows)))
Eliot Blennerhassett's avatar
Eliot Blennerhassett committed
102

103 104
    # generate_changeset_place(place, fn, outdir)
    generate_josm_tags_place(place, fn, outdir)
105

106 107
    osmchange = ET.Element('osmChange', version="0.6",
        generator="osmlinzaddr.py")
108

109
    for r in lrows:
110 111 112
        (linz_id, housenumber, street, lon, lat) = r
        if lon > 180.0:
            lon = lon - 360
Eliot Blennerhassett's avatar
Eliot Blennerhassett committed
113 114 115

        create = ET.SubElement(osmchange, "create")
        dnode = {
116 117
            'id': "-%d" % linz_id,
            'changeset': '0',
118 119
            'lat': "%8.8f" % lat,
            'lon': "%8.8f" % lon,
Eliot Blennerhassett's avatar
Eliot Blennerhassett committed
120 121 122
        }

        node = ET.SubElement(create, "node", dnode)
123
        add_tag(node, "ref:linz:address_id", str(linz_id))
124
        add_tag(node, "addr:housenumber", housenumber)
125
        add_tag(node, "addr:street", street)
126 127 128 129 130 131 132
        if include_location:
            if city is not None:
                if include_location > 1:
                    add_tag(node, "addr:city", city)
                add_tag(node, "addr:suburb", suburb)
            else:
                add_tag(node, "addr:hamlet", suburb)
Eliot Blennerhassett's avatar
Eliot Blennerhassett committed
133

134 135
    tree = ET.ElementTree(osmchange)
    tree.write(path, pretty_print=True)
Eliot Blennerhassett's avatar
Eliot Blennerhassett committed
136 137 138


if __name__ == '__main__':
139
    opts = docopt(__doc__, version='osmlinzaddr v0.2')
140 141 142 143 144
    for k in opts.keys():
        try:
            opts[k] = int(opts[k])
        except:
            pass
145 146
    print(opts)
    if True:
147 148 149 150 151 152 153
        generate_osmchange(
            opts['--database'],
            opts['--output'],
            min_nodes=opts['--min-nodes'],
            max_nodes=opts['--max-nodes'],
            include_location=opts['--include-location']
        )