187 lines
6.8 KiB
Python
187 lines
6.8 KiB
Python
#!/usr/bin/env python
|
|
import sys
|
|
import random
|
|
import json
|
|
import argparse
|
|
import re
|
|
from . import MWM, Osm2Ft, OsmIdCode
|
|
|
|
|
|
def print_json(data):
|
|
s = json.dumps(data, ensure_ascii=False, sort_keys=True)
|
|
if sys.version_info[0] >= 3:
|
|
print(s)
|
|
else:
|
|
print(s.encode('utf-8'))
|
|
|
|
|
|
def dump_mwm(args):
|
|
mwm = MWM(args.mwm)
|
|
if args.types:
|
|
mwm.read_types(args.types)
|
|
|
|
print('Tags:')
|
|
tvv = sorted([(k, v[0], v[1]) for k, v in mwm.tags.items()], key=lambda x: x[1])
|
|
for tv in tvv:
|
|
print(' {0:<8}: offs {1:9} len {2:8}'.format(tv[0], tv[1], tv[2]))
|
|
v = mwm.read_version()
|
|
print('Format: {0}, version: {1}'.format(v['fmt'], v['date'].strftime('%Y-%m-%d %H:%M')))
|
|
print('Header: {0}'.format(mwm.read_header()))
|
|
print('Region Info: {0}'.format(mwm.read_region_info()))
|
|
|
|
if args.short:
|
|
return
|
|
|
|
print('Metadata count: {0}'.format(len(mwm.read_metadata())))
|
|
|
|
cross = mwm.read_crossmwm()
|
|
if cross:
|
|
print('Outgoing points: {0}, incoming: {1}'.format(len(cross['out']), len(cross['in'])))
|
|
print('Outgoing regions: {0}'.format(set(cross['neighbours'])))
|
|
|
|
# Print some random features using reservoir sampling
|
|
count = 5
|
|
sample = []
|
|
for i, feature in enumerate(mwm.iter_features()):
|
|
if i < count:
|
|
sample.append(feature)
|
|
elif random.randint(0, i) < count:
|
|
sample[random.randint(0, count-1)] = feature
|
|
|
|
print('Feature count: {0}'.format(i))
|
|
print('Sample features:')
|
|
for feature in sample:
|
|
print_json(feature)
|
|
|
|
|
|
def find_feature(args):
|
|
mwm = MWM(args.mwm)
|
|
mwm.read_header()
|
|
if args.types:
|
|
mwm.read_types(args.types)
|
|
if args.iname:
|
|
args.iname = args.iname.lower()
|
|
|
|
for i, feature in enumerate(mwm.iter_features(metadata=True)):
|
|
if args.fid and i != args.fid:
|
|
continue
|
|
if args.name or args.iname:
|
|
if 'name' not in feature['header']:
|
|
continue
|
|
found = False
|
|
for value in feature['header']['name'].values():
|
|
if args.name and args.name in value:
|
|
found = True
|
|
elif args.iname and args.iname in value.lower():
|
|
found = True
|
|
if not found:
|
|
continue
|
|
if args.type or args.exact_type:
|
|
found = False
|
|
for t in feature['header']['types']:
|
|
if t == args.type or t == args.exact_type:
|
|
found = True
|
|
elif args.type and args.type in t:
|
|
found = True
|
|
if not found:
|
|
continue
|
|
if args.meta and ('metadata' not in feature or args.meta not in feature['metadata']):
|
|
continue
|
|
print_json(feature)
|
|
|
|
|
|
def ft2osm(args):
|
|
ft2osm = Osm2Ft(args.osm2ft, True)
|
|
code = 0
|
|
type_abbr = {'n': 'node', 'w': 'way', 'r': 'relation'}
|
|
for ftid in args.ftid:
|
|
if ftid in ft2osm:
|
|
print('https://www.openstreetmap.org/{}/{}'.format(
|
|
type_abbr[ft2osm[ftid][0]],
|
|
ft2osm[ftid][1]))
|
|
else:
|
|
print('Could not find osm id for feature {}'.format(ftid))
|
|
code = 2
|
|
return code
|
|
|
|
|
|
def decode_id(args):
|
|
if args.id.isdigit():
|
|
osm_id = OsmIdCode.unpack(int(args.id))
|
|
if osm_id is None:
|
|
print('That is not a valid identifier')
|
|
return 2
|
|
else:
|
|
type_abbr = {'n': 'node', 'w': 'way', 'r': 'relation'}
|
|
print('https://www.openstreetmap.org/{}/{}'.format(
|
|
type_abbr[osm_id[0]], osm_id[1]))
|
|
else:
|
|
m = re.search(r'/(node|way|relation)/(\d+)', args.id)
|
|
if m:
|
|
print(OsmIdCode.pack(m.group(1), int(m.group(2))))
|
|
else:
|
|
print('Please specify an URL to OSM object on its website')
|
|
return 2
|
|
|
|
|
|
def dat_to_gpx(args):
|
|
POINT_SOURCE = ['apple', 'windows', 'android', 'google', 'tizen', 'predictor']
|
|
out = sys.stdout if not args.gpx else open(args.gpx, 'w')
|
|
# TODO
|
|
print('Not implemented yet, sorry.')
|
|
return 2
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description='Toolbox for MWM files.')
|
|
parser.add_argument('-t', '--types', help='path to types.txt')
|
|
subparsers = parser.add_subparsers(dest='cmd')
|
|
subparsers.required = True
|
|
|
|
parser_dump = subparsers.add_parser('dump', help='Dumps some structures.')
|
|
parser_dump.add_argument('mwm', type=argparse.FileType('rb'), help='file to browse')
|
|
parser_dump.add_argument('-s', '--short', action='store_true',
|
|
help='Read header only, no features')
|
|
parser_dump.set_defaults(func=dump_mwm)
|
|
|
|
parser_find = subparsers.add_parser('find', help='Finds features in a file.')
|
|
parser_find.add_argument('mwm', type=argparse.FileType('rb'), help='file to search')
|
|
parser_find.add_argument('-t', dest='type',
|
|
help='look inside types ("-t hwtag" will find all hwtags-*)')
|
|
parser_find.add_argument('-et', dest='exact_type',
|
|
help='look for a type ("-et shop won\'t find shop-chemist)')
|
|
parser_find.add_argument('-n', dest='name',
|
|
help='look inside names, case-sensitive ("-n Starbucks" '
|
|
'for all starbucks)')
|
|
parser_find.add_argument('-in', '-ni', dest='iname',
|
|
help='look inside names, case-insensitive ("-in star" will '
|
|
'find Starbucks)')
|
|
parser_find.add_argument('-m', dest='meta',
|
|
help='look for a metadata key ("m flats" for features with flats)')
|
|
parser_find.add_argument('-id', dest='fid', type=int,
|
|
help='look for a feature id ("-id 1234 for feature #1234)')
|
|
parser_find.set_defaults(func=find_feature)
|
|
|
|
parser_osm = subparsers.add_parser('osm',
|
|
help='Displays an OpenStreetMap link for a feature id.')
|
|
parser_osm.add_argument('osm2ft', type=argparse.FileType('rb'), help='.mwm.osm2ft file')
|
|
parser_osm.add_argument('ftid', type=int, nargs='+', help='feature id')
|
|
parser_osm.set_defaults(func=ft2osm)
|
|
|
|
parser_id = subparsers.add_parser('id', help='Decode or encode OSM ID')
|
|
parser_id.add_argument('id', help='MWM internal OSM ID, or a link to OSM website')
|
|
parser_id.set_defaults(func=decode_id)
|
|
|
|
parser_dump = subparsers.add_parser('gpx', help='Convert gps_track.dat to GPX')
|
|
parser_dump.add_argument('dat', type=argparse.FileType('rb'), help='file to convert')
|
|
parser_dump.add_argument('--gpx', '-o', type=argparse.FileType('w'), help='output gpx file')
|
|
parser_dump.set_defaults(func=dat_to_gpx)
|
|
|
|
args = parser.parse_args()
|
|
code = args.func(args)
|
|
if code is not None:
|
|
sys.exit(code)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|