|
#!/usr/bin/env python |
|
# -*- coding: utf-8 -*- |
|
# ksjdem.py |
|
# translates DEM of National Land Numerical Information provided by MLIT into GeoTIFF |
|
# Copyright (c) 2012, Minoru Akagi. |
|
# |
|
# This program is free software: you can redistribute it and/or modify |
|
# it under the terms of the GNU General Public License as published by |
|
# the Free Software Foundation, either version 3 of the License, or |
|
# (at your option) any later version. |
|
# |
|
# This program is distributed in the hope that it will be useful, |
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
# GNU General Public License for more details. |
|
# |
|
# You should have received a copy of the GNU General Public License |
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
|
|
__version__ = 'beta 2012/05/30' |
|
|
|
import sys,os |
|
import glob |
|
import zipfile |
|
import codecs |
|
from xml.dom import minidom |
|
import numpy |
|
|
|
try: |
|
from osgeo import gdal |
|
except ImportError: |
|
import gdal |
|
|
|
try: |
|
progress = gdal.TermProgress_nocb |
|
except: |
|
progress = gdal.TermProgress |
|
|
|
GDT2nodata_value = {gdal.GDT_Byte:255, gdal.GDT_Int32:-9999, gdal.GDT_Float32:-9999, gdal.GDT_Float64:-9999} |
|
GDT2numpy = {gdal.GDT_Byte:numpy.int8, gdal.GDT_Int32:numpy.int32, gdal.GDT_Float32:numpy.float32, gdal.GDT_Float64:numpy.float64} |
|
# http://gdal.org/python/osgeo.gdalconst-module.html and http://docs.scipy.org/doc/numpy/user/basics.types.html |
|
|
|
#### data |
|
mesh_info = {} |
|
mesh_info['pid'] = {'G04':2} # 1: key=id, 2: key=pid |
|
mesh_info['level'] = {'a':[45./3600,-30./3600,80,80],'b':[4.5/3600,-3./3600,800,800],'c':[22.5/3600,-15./3600,160,160],'d':[11.25/3600,-7.5/3600,320,320]} |
|
mesh_info['pid2level'] = {} |
|
mesh_info['type'] = {'G04':[gdal.GDT_Float64] + [gdal.GDT_Float32] * 3 + [gdal.GDT_Byte,gdal.GDT_Float32] * 3} |
|
mesh_info['suffix'] = {'G04':['_meshcode','_ave_elev','_max_elev','_min_elev','_min_elev_code','_max_slope','_max_slope_dir','_min_slope','_min_slope_dir','_ave_slope']} |
|
mesh_info['color_table'] = {'G04':{0:(0,0,0),1:(255,255,255),2:(191,191,191),3:(127,127,127),4:(63,63,63),5:(0,0,0),6:(63,63,63),7:(127,127,127),8:(191,191,191)}} |
|
#### |
|
|
|
# ksjmesh2geotiff |
|
def ksjmesh2geotiff(src_file,dst_dir,att_numbers,driver,create_options = [],init_value = None): |
|
if src_file.find('tky') != -1: |
|
print 'unsupport file.', src_file |
|
sys.exit(1) |
|
|
|
if quiet == 0: |
|
print 'parsing %s...' % src_file, |
|
|
|
xml = minidom.parse(src_file) |
|
|
|
if quiet == 0: |
|
print 'ok' |
|
if debug_mode: |
|
print 'schemaLocation : %s' % xml.childNodes[0].attributes['xsi:schemaLocation'].value |
|
print 'description : %s' % xml.getElementsByTagName('gml:description')[0].childNodes[0].data |
|
|
|
p = os.path.basename(src_file).split('_')[0].split('-') |
|
p.pop() |
|
if len(p) == 2: |
|
id = '-'.join(p) |
|
pid, level = id.split('-') |
|
else: |
|
id = pid = p[0] |
|
level = mesh_info['pid2level'][pid] |
|
|
|
if pid in mesh_info['pid'] and level in mesh_info['level']: |
|
if mesh_info['pid'][pid] == 1: |
|
key = id |
|
else: |
|
key = pid |
|
psize_x,psize_y,xsize,ysize = mesh_info['level'][level] |
|
else: |
|
print 'Cannot read %s. Unsupport file.' % src_file |
|
sys.exit(1) |
|
|
|
lry, ulx = map(float2, xml.getElementsByTagName('gml:lowerCorner')[0].childNodes[0].data.split(' ')) |
|
uly, lrx = map(float2, xml.getElementsByTagName('gml:upperCorner')[0].childNodes[0].data.split(' ')) |
|
geotransform = [ulx, psize_x, 0, uly, 0, psize_y] |
|
|
|
tupleList = xml.getElementsByTagName('gml:tupleList') |
|
|
|
if att_numbers is None: |
|
att_numbers = range(2,len(mesh_info['type'][key])+1) |
|
|
|
if debug_mode: |
|
print 'bounds : %f, %f - %f, %f' % (lry,ulx,uly,lrx) |
|
print 'cell size : %f, %f' % (psize_x,psize_y) |
|
print 'number of tupleList : %d' % len(tupleList) |
|
print 'attribute numbers :', att_numbers |
|
|
|
filetitle = os.path.splitext(os.path.basename(src_file))[0] |
|
ext = '.tif' |
|
bands = 1 |
|
att_processed = 0 |
|
for an in att_numbers: |
|
an_1 = an - 1 |
|
band_type = mesh_info['type'][key][an_1] |
|
if debug_mode: |
|
print 'an:%d suffix:%s, data type:%d' % (an,mesh_info['suffix'][key][an_1],band_type) |
|
if band_type: |
|
filename = filetitle + mesh_info['suffix'][key][an_1] + ext |
|
filepath = os.path.join(dst_dir, filename) |
|
|
|
if quiet == 0: |
|
print filename + '...', |
|
|
|
dst_ds = driver.Create(filepath, xsize, ysize, bands, band_type, create_options) |
|
if dst_ds is None: |
|
print 'Creation failed.' |
|
sys.exit(1) |
|
|
|
dst_ds.SetGeoTransform(geotransform) |
|
# The following Well Known Text of CRS has been quoted from http://spatialreference.org/ref/epsg/4612/ogcwkt/ |
|
dst_ds.SetProjection('GEOGCS["JGD2000",DATUM["Japanese_Geodetic_Datum_2000",SPHEROID["GRS 1980",6378137,298.257222101,AUTHORITY["EPSG","7019"]],TOWGS84[0,0,0,0,0,0,0],AUTHORITY["EPSG","6612"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.01745329251994328,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4612"]]') |
|
|
|
if init_value is None: |
|
nv = GDT2nodata_value[band_type] |
|
else: |
|
nv = init_value |
|
|
|
narray = numpy.empty((ysize,xsize),GDT2numpy[band_type]) |
|
narray.fill(nv) |
|
|
|
for tl in tupleList: |
|
rows = tl.childNodes[0].data.strip().split("\n") |
|
for row in rows: |
|
fields = row.split(",") |
|
meshcode = fields[0] |
|
if level == 'd': |
|
c8 = int(meshcode[8]) - 1 |
|
c9 = int(meshcode[9]) - 1 |
|
x = int(meshcode[5]) * 40 + int(meshcode[7]) * 4 + (c8 % 2) * 2 + (c9 % 2) |
|
y = ysize - 1 - (int(meshcode[4]) * 40 + int(meshcode[6]) * 4 + (c8 // 2) * 2 + (c9 // 2)) |
|
elif level == 'c': |
|
c8 = int(meshcode[8]) - 1 |
|
x = int(meshcode[5]) * 20 + int(meshcode[7]) * 2 + (c8 % 2) |
|
y = ysize - 1 - (int(meshcode[4]) * 20 + int(meshcode[6]) * 2 + (c8 // 2)) |
|
elif level == 'b': |
|
x = int(meshcode[5]) * 100 + int(meshcode[7]) * 10 + int(meshcode[9]) |
|
y = ysize - 1 - (int(meshcode[4]) * 100 + int(meshcode[6]) * 10 + int(meshcode[8])) |
|
else: # level == 'a' |
|
x = int(meshcode[5]) * 10 + int(meshcode[7]) |
|
y = ysize - 1 - (int(meshcode[4]) * 10 + int(meshcode[6])) |
|
|
|
if fields[an_1] != 'unknown': |
|
if band_type == gdal.GDT_Byte: |
|
if key == 'L03-b': |
|
narray[y][x] = tochiriyo2int(fields[an_1]) |
|
else: |
|
narray[y][x] = int(fields[an_1]) |
|
elif band_type == gdal.GDT_Int32: |
|
narray[y][x] = int(fields[an_1]) |
|
else: |
|
narray[y][x] = float(fields[an_1]) |
|
|
|
rband = dst_ds.GetRasterBand(1) |
|
rband.WriteArray(narray,0,0) |
|
if init_value is None: |
|
rband.SetNoDataValue(nv) |
|
if band_type == gdal.GDT_Byte: |
|
rband.SetColorTable(create_color_table(key)) |
|
|
|
dst_ds = None |
|
|
|
if quiet == 0: |
|
print 'ok' |
|
|
|
att_processed += 1 |
|
# if quiet == 0 and verbose == 0: |
|
# progress(att_processed / float(len(att_numbers))) |
|
|
|
def tochiriyo2int(val): |
|
i = ord(val) |
|
if i < 65: |
|
return i - 48 |
|
return i - 55 |
|
|
|
def create_color_table(key): |
|
table = gdal.ColorTable() |
|
entries = mesh_info['color_table'][key] |
|
for i in entries: |
|
table.SetColorEntry(i,entries[i]) |
|
return table |
|
|
|
def unzip_xml(src_file, dest=None): |
|
if not os.path.isfile(src_file): |
|
return None |
|
|
|
if dest is None: |
|
dest = os.path.splitext(src_file)[0] |
|
zf = zipfile.ZipFile(src_file, mode='r') |
|
names = zf.namelist() |
|
|
|
if verbose: |
|
print 'files\n%s' % '\n'.join(names) |
|
|
|
for n in names: |
|
if os.path.splitext(n)[1] == '.xml' and n.find('META') == -1: |
|
zf.extract(n,dest) |
|
zf.close() |
|
|
|
if verbose: |
|
print('unzipped : '+names[0]) |
|
|
|
return os.path.join(dest,n) |
|
zf.close() |
|
|
|
def float2(str): |
|
lc = '' |
|
for i in range(len(str)): |
|
c = str[i] |
|
if c == lc: |
|
renzoku += 1 |
|
if renzoku == 5: # |
|
return float(str[:i+1] + c * 11) # |
|
else: |
|
lc = c |
|
renzoku = 1 |
|
return float(str) |
|
|
|
def Usage(): |
|
print '=== Usage ===' |
|
print 'python ksjdem.py [-out_dir output_directory][-init value][-an attribute_number(s)][-q] [-v] src_files*' |
|
print '' |
|
print 'src_files: The source file name(s). JPGIS 2.1(GML) zip/xml files.' |
|
print 'You can use -version option to display the version of this script.' |
|
return 0 |
|
|
|
def main(argv=None): |
|
global verbose, quiet, debug_mode |
|
verbose = 0 |
|
quiet = 0 |
|
debug_mode = 0 |
|
format = 'GTiff' |
|
filenames = [] |
|
out_dir = '' |
|
att_numbers = [2] |
|
init_value = None |
|
|
|
gdal.AllRegister() |
|
|
|
if argv is None: |
|
argv = sys.argv |
|
argv = gdal.GeneralCmdLineProcessor(argv) |
|
if argv is None: |
|
return 0 |
|
|
|
# Parse command line arguments. |
|
i = 1 |
|
while i < len(argv): |
|
arg = argv[i] |
|
|
|
if arg == '-init': |
|
i += 1 |
|
init_value = int(argv[i]) |
|
|
|
elif arg == '-an': |
|
i += 1 |
|
att_numbers = map(int,argv[i].split(',')) |
|
|
|
elif arg == '-out_dir': |
|
i += 1 |
|
out_dir = argv[i] |
|
|
|
elif arg == '-v': |
|
verbose = 1 |
|
|
|
elif arg == '-q': |
|
quiet = 1 |
|
|
|
elif arg == '-debug': |
|
debug_mode = 1 |
|
|
|
elif arg == '-help' or arg == '--help': |
|
return Usage() |
|
|
|
elif arg == '-version': |
|
print 'ksjdem.py Version %s' % __version__ |
|
return 0 |
|
|
|
elif arg[:1] == '-': |
|
print 'Unrecognised command option: %s' % arg |
|
return Usage() |
|
|
|
else: |
|
# Expand any possible wildcards |
|
f = glob.glob(arg) |
|
if len(f) == 0: |
|
print 'File not found: "%s"' % arg |
|
|
|
filenames += f |
|
|
|
i = i + 1 |
|
|
|
if verbose or debug_mode: |
|
sys.stdout = codecs.getwriter('shift_jis')(sys.stdout) # Error occurs in Python >= 3.0 |
|
if debug_mode: |
|
print 'args: %s' % ' '.join(argv) |
|
print 'files: %s' % ','.join(filenames) |
|
|
|
if len(filenames) == 0: |
|
print 'No input files selected.' |
|
return Usage() |
|
|
|
if out_dir != '' and os.path.exists(out_dir) == False: |
|
os.mkdir(out_dir) |
|
if verbose: |
|
print '"%s" directory has been created.' % out_dir |
|
|
|
driver = gdal.GetDriverByName(format) |
|
if driver is None: |
|
print 'Format driver %s not found.' % format |
|
return 0 |
|
|
|
fi_processed = 0 |
|
for src_file in filenames: |
|
if quiet == 0 and len(filenames) > 1: |
|
print 'Processing files ( %d / %d )' % (fi_processed+1, len(filenames)) |
|
|
|
src_root, ext = os.path.splitext(src_file) |
|
if out_dir == '': |
|
dst_root = src_root |
|
else: |
|
dst_root = out_dir |
|
|
|
ext = ext.lower() |
|
if ext == '.zip': |
|
if quiet == 0: |
|
print 'extracting %s...' % src_file, |
|
|
|
file_in = unzip_xml(src_file,dst_root) |
|
|
|
if quiet == 0: |
|
print 'ok' |
|
|
|
ksjmesh2geotiff(file_in,dst_root,att_numbers,driver,[],init_value) |
|
|
|
os.remove(file_in) |
|
|
|
if verbose: |
|
print 'Temporary files have been removed.' |
|
if quiet == 0: |
|
print '' |
|
|
|
elif ext == '.xml': |
|
if src_file.find('META') == -1: |
|
if os.path.exists(dst_root) == False: |
|
os.mkdir(dst_root) |
|
|
|
ksjmesh2geotiff(src_file,dst_root,att_numbers,driver,[],init_value) |
|
else: |
|
print '%s is META file.' % src_file |
|
|
|
fi_processed += 1 |
|
|
|
if quiet == 0: |
|
print 'completed' |
|
return 0 |
|
|
|
if __name__ == '__main__': |
|
sys.exit(main()) |