From b1ae14879ce3fca96158ed60bfde683c6ca5438b Mon Sep 17 00:00:00 2001 From: Andreas Demmelbauer Date: Thu, 16 Sep 2021 23:44:23 +0200 Subject: [PATCH] new version --- canvas.svg | 7 +- convert-svg-to-gistiff.py | 378 ++++++++++++++++++++++++++++++++++++++ export-gis-jpg.py | 263 -------------------------- gis-svg-stitcher.py | 248 +++++++++++++++---------- 4 files changed, 532 insertions(+), 364 deletions(-) create mode 100644 convert-svg-to-gistiff.py delete mode 100644 export-gis-jpg.py diff --git a/canvas.svg b/canvas.svg index 878d9ea..6ccdab3 100644 --- a/canvas.svg +++ b/canvas.svg @@ -19,9 +19,6 @@ xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"> - + Y vertical +# if key == 'exif:GPSLongitude': +# # print('lonstr', value) +# lon = deg_coordinates_to_decimal(value) # lon -> X horizontal + +# return [lat, lon] + + +# def get_coordinate_boundaries(): +# image_names = get_used_tiles_relpaths() +# coordinates = { +# 'lat': [], +# 'lon': [] +# } +# for filename in image_names: +# tile_coordinates = read_coordinates_from_tile(filename) +# coordinates['lat'].append(tile_coordinates[0]) +# coordinates['lon'].append(tile_coordinates[1]) + +# boundaries = { +# 'xmin': min(coordinates['lon']), +# 'xmax': max(coordinates['lon']), +# 'ymin': min(coordinates['lat']), +# 'ymax': max(coordinates['lat']), +# } +# return boundaries + + +# def create_ungrouped_svg(): +# """ +# exports the SVG without any grouped elements +# (the quick and dirty way) +# """ +# print('Create an SVG without groups ...') +# inkscape_actions = "select-all:groups; SelectionUnGroup; select-all:groups; SelectionUnGroup; select-all:groups; SelectionUnGroup; select-all:groups; SelectionUnGroup; select-all:groups; SelectionUnGroup; select-all:groups; SelectionUnGroup; select-all:groups; SelectionUnGroup; export-filename: {}; export-plain-svg; export-do;".format(TEMP_MAP_UNGROUPED_SVG_PATH) +# command = [ +# '/snap/bin/inkscape', +# '--pipe', +# '--actions={}'.format(inkscape_actions), +# ], +# input_file = open(INPUT_PATH, "rb") +# completed = subprocess.run( +# *command, +# cwd=INPUT_DIR, # needed for reative image links +# stdin=input_file, +# ) +# print('completed', completed) +# return completed + + +def get_ground_control_points(): + """ + Using selenium with firefox for rendering the SVG and + getting the positional matching between GPS + and x/y coords of SVG-image. + image tags need to have the gps data attached as data attributes. + """ + print('Getting ground control points ...') + options = webdriver.firefox.options.Options() + options.headless = True + driver = webdriver.Firefox(options=options) + driver.get("file://{}".format(INPUT_PATH)) + images = driver.find_elements_by_class_name("thermal_image") + + gcps = [] + for image in images: + location = image.location + size = image.size + raster_y = float(location['y'] + size['height']/2) + raster_x = float(location['x'] + size['width']/2) + reference_lon = float(image.get_attribute('data-lon')) + reference_lat = float(image.get_attribute('data-lat')) + imageMapping = rasterio.control.GroundControlPoint(row=raster_y, col=raster_x, x=reference_lon, y=reference_lat) + gcps.append(imageMapping) + + driver.quit() + return gcps + + +# def make_vector_shapefile(): +# w = shapefile.Writer(VECTOR_SHAPEFILE_PATH) +# w.field('name', 'C') + +# tree = ET.parse(INPUT_PATH) +# root = tree.getroot() +# tiles = root.xpath('//*[@class="thermal_image"]') +# for index, tile in enumerate(tiles): +# w.point(float(tile.attrib['data-lon']), float(tile.attrib['data-lat'])) +# w.record('point{}'.format(index)) +# w.close() +# return True + +def verify_coordinate_matching(): + """ + During development, i want to proof + that the point/coordinate matching is right. + Producing a png file with red dots for visual proof. + """ + img = cv2.imread(TEMP_MAP_THERMALPNG_PATH, cv2.IMREAD_GRAYSCALE) + img = cv2.cvtColor(img,cv2.COLOR_GRAY2RGB) + + options = webdriver.firefox.options.Options() + # options.headless = True + driver = webdriver.Firefox(options=options) + driver.get("file://{}".format(INPUT_PATH)) + images = driver.find_elements_by_class_name("thermal_image") + + gcps = [] + for image in images: + location = image.location + size = image.size + raster_y = int(location['y'] + size['height']/2) + raster_x = int(location['x'] + size['width']/2) + reference_lon = float(image.get_attribute('data-lon')) + reference_lat = float(image.get_attribute('data-lat')) + print(raster_x, raster_y) + img = cv2.circle(img, (raster_x, raster_y), radius=10, color=(0, 0, 255), thickness=-1) + driver.quit() + cv2.imwrite(TEMP_MAP_ALIGNMENTPROOF_PATH, img) + + + + +def make_geotiff_image(): + + thermal_numpy_array = get_thermal_numpy_array() + thermal_numpy_array[thermal_numpy_array == 0] = np.NaN # zeros to NaN + + # # coordinates of all tiles + # geo_bound = get_coordinate_boundaries() + # print('boundaries', geo_bound) + + np_shape = thermal_numpy_array.shape + image_size = (np_shape[0], np_shape[1]) + + gcps = get_ground_control_points() + print('Applying affine transform ...') + gcp_transform = rasterio.transform.from_gcps(gcps) + print(gcp_transform) + + print('Generating the GeoTiff ...') + + raster_io_dataset = rasterio.open( + OUTPUT_PATH, + 'w', + driver='GTiff', + height=thermal_numpy_array.shape[0], + width=thermal_numpy_array.shape[1], + count=1, + dtype=thermal_numpy_array.dtype, + transform=gcp_transform, + crs='+proj=latlong', + ) + raster_io_dataset.write(thermal_numpy_array, 1) + + # # try to get rid of the black frame + # src = rasterio.open(OUTPUT_PATH) + # src[src == 0] = np.NaN # zeros to NaN + # raster_io_dataset2 = rasterio.open( + # OUTPUT_PATH, + # 'w', + # driver='GTiff', + # height=src.shape[0], + # width=src.shape[1], + # count=1, + # dtype=src.dtype, + # crs='+proj=latlong', + # ) + # raster_io_dataset2.write(src, 1) + + print('Saved to ', OUTPUT_PATH) + + + +# make_thermalpng_tiles() +make_thermalpng_svg() +make_thermalpng() +make_geotiff_image() + +# # Helpers for debugging +# verify_coordinate_matching() +# make_vector_shapefile() diff --git a/export-gis-jpg.py b/export-gis-jpg.py deleted file mode 100644 index c14a5c3..0000000 --- a/export-gis-jpg.py +++ /dev/null @@ -1,263 +0,0 @@ -import os -import argparse -import lxml.etree as ET -import subprocess -import flirimageextractor -import cv2 -import numpy as np -from pathlib import Path -from wand.image import Image -from osgeo import gdal -from osgeo import osr - -arg_parser = argparse.ArgumentParser(description='Export SVG composition of FLIR images as TIFF with thermo layer') - -arg_parser.add_argument('Input', - metavar='input_svg', - type=str, - help='Path to the input SVG file cotaining xlinks to FLIR images') - -arg_parser.add_argument('Output', - metavar='output_tiff', - type=str, - help='Output filename') - - -args = arg_parser.parse_args() -dirname = os.path.dirname(__file__) -INPUT_PATH = os.path.join(dirname, args.Input) -INPUT_DIR = os.path.split(INPUT_PATH)[0] - -TEMP_MAP_THERMALPNG_SVG_PATH = os.path.join(INPUT_DIR, 'map_thermalpng.svg') -TEMP_MAP_THERMALPNG_PATH = os.path.join(INPUT_DIR, 'map_thermalpng.png') -TEMP_MAP_PREVIEW_PATH = os.path.join(INPUT_DIR, 'map_preview.png') -THERMALPNG_DIR = 'thermalpngs' - -OUTPUT_PATH = os.path.join(dirname, args.Output) - - - -def make_thermalpng_tiles(): - """ - Extract thermal infomration as greyscale PNG-16 (temp * 1000 to retain some decimals) - and save the png tiles - """ - Path(os.path.join(INPUT_DIR, THERMALPNG_DIR)).mkdir(parents=True, exist_ok=True) - png_output_dir = os.path.join(INPUT_DIR, THERMALPNG_DIR) - - for root_path, directories, file in os.walk(os.path.join(dirname, INPUT_DIR)): - for file in file: - if(file.endswith(".jpg")): - print('Extracting thermal info from ' + file) - full_filepath = os.path.join(root_path, file) - flir = flirimageextractor.FlirImageExtractor() - flir.process_image(full_filepath) - thermal_img_np = flir.thermal_image_np - multiplied_image = cv2.multiply(thermal_img_np, 1000) - output_file_path = os.path.join(png_output_dir, file + '.thermal.png') - print(output_file_path) - cv2.imwrite(output_file_path, multiplied_image.astype(np.uint16)) - - - - -def make_thermalpng_svg(): - """ - replaces the image paths with the thermal pngs - and creates new SVG file - """ - # print("svg_file") - # print(dir(svg_file)) - tree = ET.parse(INPUT_PATH) - root = tree.getroot() - # print(ET.tostring(root)) - # tile_rows = root.xpath('//image', namespaces={'n': "http://www.w3.org/2000/svg"}) - # print(dir(root)) - tile_elements = root.xpath('//*[@class="thermal_image"]') - linkattrib ='{http://www.w3.org/1999/xlink}href' - for tile in tile_elements: - tile.attrib[linkattrib] = os.path.join(THERMALPNG_DIR, tile.attrib[linkattrib] + '.thermal.png') - # newxml = ET.tostring(tree, encoding="unicode") - # print(newxml) - # return newxml - - with open(TEMP_MAP_THERMALPNG_SVG_PATH, 'wb') as f: - tree.write(f, encoding='utf-8') - - return tree - - - -def make_thermalpng(): - """ - exports the SVG canvas as Gray_16 PNG - """ - command = [ - '/snap/bin/inkscape', - '--pipe', - '--export-type=png', - '--export-png-color-mode=Gray_16' - ], - input_file = open(TEMP_MAP_THERMALPNG_SVG_PATH, "rb") - output_file = open(TEMP_MAP_THERMALPNG_PATH, "wb") - completed = subprocess.run( - *command, - cwd=INPUT_DIR, # needed for reative image links - stdin=input_file, - stdout=output_file - ) - return completed - -def make_thermalpreview(): - """ - exports the preview image - """ - command = [ - '/snap/bin/inkscape', - '--pipe', - '--export-type=png', - '--export-png-color-mode=Gray_8' - ], - input_file = open(TEMP_MAP_THERMALPNG_SVG_PATH, "rb") - output_file = open(TEMP_MAP_PREVIEW_PATH, "wb") - completed = subprocess.run( - *command, - cwd=INPUT_DIR, # needed for reative image links - stdin=input_file, - stdout=output_file - ) - return completed - -# def make_thermalpreview(): -# """ -# exports the preview image -# """ -# command = [ -# '/snap/bin/inkscape', -# '--pipe', -# '--export-type=png', -# '--export-png-color-mode=Gray_8' -# ] -# input_file = open(TEMP_MAP_THERMALPNG_SVG_PATH, "rb") -# output_file = open(TEMP_MAP_PREVIEW_PATH, "wb") -# completed = subprocess.run( -# *command, -# cwd=INPUT_DIR, # needed for reative image links -# stdin=input_file, -# stdout=output_file -# ) -# return completed - - -def get_thermal_numpy_array(): - # input_file = open(TEMP_MAP_THERMALPNG_PATH, "rb") - image = cv2.imread(TEMP_MAP_THERMALPNG_PATH, cv2.IMREAD_ANYDEPTH) - image_float = image.astype(np.float32) - image_float_normalized = cv2.divide(image_float, 1000) - print(image_float_normalized[1000][905]) - # cv2.imshow("OpenCV Image Reading", image) - return image_float_normalized - -def get_used_tiles_relpaths(): - """ - outputs an array of all used tile filenames in the input SVG - (relative filepaths like they appear in the svg.) - """ - images = [] - tree = ET.parse(INPUT_PATH) - root = tree.getroot() - tile_elements = root.xpath('//*[@class="thermal_image"]') - linkattrib ='{http://www.w3.org/1999/xlink}href' - for tile in tile_elements: - images.append(tile.attrib[linkattrib]) - return images - -def deg_coordinates_to_decimal(coordStr): - coordArr = coordStr.split(', ') - calculatedCoordArray = [] - for calculation in coordArr: - calculationArr = calculation.split('/') - calculatedCoordArray.append(int(calculationArr[0]) / int(calculationArr[1])) - degrees = calculatedCoordArray[0] - minutes = calculatedCoordArray[1] - seconds = calculatedCoordArray[2] - decimal = (degrees + (minutes * 1/60) + (seconds * 1/60 * 1/60)) - # print(decimal) - return decimal - - -def read_coordinates_from_tile(filename): - full_filepath = os.path.join(INPUT_DIR, filename) - with Image(filename=full_filepath) as image: - for key, value in image.metadata.items(): - if key == 'exif:GPSLatitude': - # print('latstr', value) - lat = deg_coordinates_to_decimal(value) # lat -> Y vertical - if key == 'exif:GPSLongitude': - # print('lonstr', value) - lon = deg_coordinates_to_decimal(value) # lon -> X horizontal - if key == 'exif:GPSImgDirection': - direction = value.split('/') - print(int(direction[0])/int(direction[1])/2, ' ', (value)) - - return [lat, lon] - -def get_coordinate_boundaries(): - image_names = get_used_tiles_relpaths() - coordinates = { - 'lat': [], - 'lon': [] - } - for filename in image_names: - tile_coordinates = read_coordinates_from_tile(filename) - coordinates['lat'].append(tile_coordinates[0]) - coordinates['lon'].append(tile_coordinates[1]) - - boundaries = { - 'xmin': min(coordinates['lon']), - 'xmax': max(coordinates['lon']), - 'ymin': min(coordinates['lat']), - 'ymax': max(coordinates['lat']), - } - return boundaries - - -def make_geotiff_image(): - thermal_numpy_array = get_thermal_numpy_array() - - # coordinates of all tiles - geo_bound = get_coordinate_boundaries() - print('boundaries', geo_bound) - - np_shape = thermal_numpy_array.shape - image_size = (np_shape[0], np_shape[1]) - - # set geotransform - nx = image_size[0] - ny = image_size[1] - xres = (geo_bound['xmax'] - geo_bound['xmin']) / float(nx) - yres = (geo_bound['ymax'] - geo_bound['ymin']) / float(ny) - geotransform = (geo_bound['xmin'], xres, 0, geo_bound['ymax'], 0, -yres) - - # create the 3-band raster file - dst_ds = gdal.GetDriverByName('GTiff').Create(OUTPUT_PATH, ny, nx, 1, gdal.GDT_Float32) - dst_ds.SetGeoTransform(geotransform) # specify coords - srs = osr.SpatialReference() # establish encoding - res = srs.SetWellKnownGeogCS( "WGS84" ) # WGS84 lat/long - dst_ds.SetProjection(srs.ExportToWkt()) # export coords to file - dst_ds.GetRasterBand(1).WriteArray(thermal_numpy_array) # write thermal-band to the raster - dst_ds.FlushCache() # write to disk - - - - -# make_thermalpng_tiles() -# make_thermalpng_svg() -# make_thermalpreview() -# make_thermalpng() -make_geotiff_image() - - -# dataset = gdal.Open("working_result_example.tif", gdal.GA_ReadOnly) -# print(dir(dataset)) -# print(dataset.GetMetadata_List()) diff --git a/gis-svg-stitcher.py b/gis-svg-stitcher.py index 3853cc0..0544f57 100644 --- a/gis-svg-stitcher.py +++ b/gis-svg-stitcher.py @@ -1,23 +1,48 @@ -from wand.image import Image -import PIL.Image -import io -import exiftool -import subprocess import os +import argparse +from wand.image import Image import lxml.etree as ET import copy +import math + + +from pyproj import CRS +from pyproj.aoi import AreaOfInterest +from pyproj.database import query_utm_crs_info +from pyproj import Transformer + + + +arg_parser = argparse.ArgumentParser(description='Place drone FLIR-tiles into a SVG in order to edit them in Inkscape') -import cv2 -import flirimageextractor -from matplotlib import cm -import numpy as np -import urllib.request +arg_parser.add_argument('Input', + metavar='input_directory', + type=str, + help='Path where the FLIR tiles are') +arg_parser.add_argument( + '--base_rotation', action='store', default=115, + help="Base orientation of drone in degrees (0-360) Defaults to 115", + type=int, dest='base_rotation' +) + +arg_parser.add_argument( + '--scale', action='store', default=15, + help="Scaling (higher number leads to bigger canvas and less dense tiles) (defaults to 15)", + type=int, dest='scale' +) + + + + +args = arg_parser.parse_args() + dirname = os.path.dirname(__file__) -working_dir = 'source_images_full' +working_dir = args.Input +OUTPUT_PATH = os.path.join(working_dir,'map.svg') filename = os.path.join(dirname, 'canvas.svg') @@ -42,25 +67,10 @@ def deg_coordinates_to_decimal(coordStr): seconds = calculatedCoordArray[2] return (degrees + (minutes * 1/60) + (seconds * 1/60 * 1/60)) -# # extracting TIF Data -# for root, directories, file in os.walk(os.path.join(dirname, working_dir)): -# for file in file: -# if(file.endswith(".jpg")): -# print(os.path.join(root, file)) -# full_filepath = os.path.join(root, file) -# with exiftool.ExifTool() as et: -# cmd = ['exiftool', full_filepath, "-b", "-RawThermalImage"] -# tif_data = subprocess.check_output(cmd) -# tif_image = PIL.Image.open(io.BytesIO(tif_data)) -# tif_filepath = os.path.join(dirname, working_dir, file.split('.')[0] + '_thermal.tif') -# tif_image.save(tif_filepath) -# print(tif_filepath) - - - # finding the boundaries of the whole canvas latsArr = [] lonsArr = [] + for root_path, directories, file in os.walk(os.path.join(dirname, working_dir)): for file in file: if(file.endswith(".jpg")): @@ -86,24 +96,71 @@ minLat = min(latsArr) minLon = min(lonsArr) maxLat = max(latsArr) maxLon = max(lonsArr) -width = maxLon - minLon -height = maxLat- minLat +midLon = (minLon + maxLon) /2 +midLat = (minLat + maxLat) /2 + + + +# find CRS system +utm_crs_list = query_utm_crs_info( + datum_name="WGS 84", + area_of_interest=AreaOfInterest( + west_lon_degree=minLon, + south_lat_degree=minLat, + east_lon_degree=maxLon, + north_lat_degree=maxLat, + ), +) +utm_crs = CRS.from_epsg(utm_crs_list[0].code) +transformer = Transformer.from_crs("EPSG:4326", utm_crs, always_xy=True) + +min_transformed_lon, min_transformed_lat = transformer.transform(minLon, minLat) +max_transformed_lon, max_transformed_lat = transformer.transform(maxLon, maxLat) + + +width = max_transformed_lon - min_transformed_lon +height = max_transformed_lat - min_transformed_lat + + + +# def latlngToGlobalXY(lat, lng): +# earth_radius = 6371 +# # Calculates x based on cos of average of the latitudes +# x = earth_radius * lng * math.cos((minLat + maxLat)/2) +# # Calculates y based on latitude +# y = earth_radius * lat +# return {x: x, y: y} + +# def latlngToScreenXY(lat, lng): +# topLeft_corner = latlngToGlobalXY(minLat, minLon) +# bottomRight_corner = latlngToGlobalXY(maxLat, maxLon) +# # Calculate global X and Y for projection point +# pos = latlngToGlobalXY(lat, lng) +# # Calculate the percentage of Global X position in relation to total global width +# pos.perX = ((pos.x - topLeft_corner.x) / (bottomRight_corner.x - topLeft_corner.x)) +# # Calculate the percentage of Global Y position in relation to total global height +# pos.perY = ((pos.y - topLeft_corner.y) / (bottomRight_corner.y - topLeft_corner.y)) + +# # Returns the screen position based on reference points +# return { +# x: p0.scrX + (p1.scrX - p0.scrX)*pos.perX, +# y: p0.scrY + (p1.scrY - p0.scrY)*pos.perY +# } + + # placing the images into the svg -rotation = 125 -y_scale = -1800000 #-400000 -x_scale = 655000 #-950000 -# y_scale = 2600000 #-400000 -# x_scale = 1200000 #-950000 -image_rotation_up = rotation #32 -image_rotation_down = rotation + 180 #192 + + +# image_rotation_up = rotation #32 +# image_rotation_down = rotation + 180 #192 for root_path, directories, file in os.walk(os.path.join(dirname, working_dir)): for file in file: @@ -111,52 +168,48 @@ for root_path, directories, file in os.walk(os.path.join(dirname, working_dir)): print(os.path.join(root_path, file)) full_filepath = os.path.join(root_path, file) with Image(filename=full_filepath) as image: - print(image.width) - print(image.height) + # print(image.width) + # print(image.height) for key, value in image.metadata.items(): # print("{}: {}".format(key, value)) if key == 'exif:GPSLatitude': - lat = deg_coordinates_to_decimal(value) - minLat - print('lat '+ str(lat)) + lat = deg_coordinates_to_decimal(value) + lat_offset = lat - minLat if key == 'exif:GPSLongitude': - lon = deg_coordinates_to_decimal(value) - minLon - print('lon '+ str(lon)) + lon = deg_coordinates_to_decimal(value) + lon_offset = lon - minLon if key == 'exif:GPSImgDirection': direction = value.split('/') - rotation = int(direction[0])/int(direction[1])/2 - + rotation = ( int(direction[0]) / int(direction[1]) ) / 2 + args.base_rotation + print('rotation',rotation) + transformed_lon, transformed_lat = transformer.transform(lon, lat) + lon_offset = transformed_lon - min_transformed_lon + lat_offset = transformed_lat - min_transformed_lat + # print(transformed_lon, min_transformed_lon, transformed_lat, min_transformed_lat) + # print('lon_offset, lat_offset', lon_offset, lat_offset) g_pos_el_attributes = { - # 'x': str(lat*scale), - # 'y': str(lon*scale), - 'transform': "translate({}, {})".format(format(lon*x_scale, '.20f'), format(lat*y_scale, '.20f')), - 'data-lat': format(lat, '.20f'), - 'data-lon': format(lon, '.20f'), + 'transform': "translate({}, {})".format(format(lon_offset*args.scale, '.20f'), format(lat_offset*args.scale*-1, '.20f')), + 'data-lat-offset': format(lat_offset, '.20f'), + 'data-lon-offset': format(lon_offset, '.20f'), 'class': 'tile', 'id': 'tile_{}'.format(file.split('.')[0]), - # 'style': 'opacity:.6', } g_pos_el = ET.SubElement(main_layer, 'g', attrib=g_pos_el_attributes) g_offset_corr_el_attributes = { - 'transform': "translate(150, 0)", + 'transform': "translate({}, {})".format(-image.width/2, -image.height/2), 'class': 'tile-offset-corr', } g_offset_corr_el = ET.SubElement(g_pos_el, 'g', attrib=g_offset_corr_el_attributes) - - g_center_el_attributes = { - 'class': 'tile-center', - 'transform': 'translate({}, {})'.format(str(image.width/2*-1), str(image.height/2*-1)) - } - g_center_el = ET.SubElement(g_offset_corr_el, 'g', attrib=g_center_el_attributes) - g_rot_el_attributes = { 'class': 'tile-rotate', - 'data-image-rotation': str(image_rotation_up), - 'data-image-dimensions': str(image.width/2) + ' ' + str(image.height/2), - 'transform': 'rotate({} {} {})'.format(str(image_rotation_up), str(image.width/2), str(image.height/2)) + 'data-image-rotation': str(rotation), + 'data-image-dimensions': str(image.width) + ' ' + str(image.height), + 'transform': 'rotate({} {} {})'.format(str(rotation), str(image.width/2), str(image.height/2)) + # 'transform': 'rotate({} {} {})'.format(str(rotation), 0,0) } - g_rot_el = ET.SubElement(g_center_el, 'g', attrib=g_rot_el_attributes) + g_rot_el = ET.SubElement(g_offset_corr_el, 'g', attrib=g_rot_el_attributes) xlinkns ="http://www.w3.org/1999/xlink" image_el = ET.SubElement(g_rot_el, 'image', { @@ -164,14 +217,10 @@ for root_path, directories, file in os.walk(os.path.join(dirname, working_dir)): "{%s}href" % xlinkns: file, "width": str(image.width), "height": str(image.height), - "mask" : "url(#tilefademask)", + 'data-lat': format(lat, '.20f'), + 'data-lon': format(lon, '.20f'), }) -# transform_str = "translate(-{}, -{})".format(str(min(latsArr)*scale), str(min(lonsArr)*scale)) -# print(transform_str) -# main_layer.attrib['transform'] = transform_str - - # sort elements def getkey(elem): @@ -184,55 +233,62 @@ def getkey(elem): main_layer[:] = sorted(main_layer, key=getkey) -# rotate image if previous element is under the current one +# find rows +# up/down is actually left/right or right/left last_state = 'down' for index, el in enumerate(main_layer): if(el.getprevious() is not None): - if (el.getprevious().attrib['data-lon'] > el.attrib['data-lon'] or (el.getprevious().attrib['data-lon'] == el.attrib['data-lon'] and last_state == 'up')): + if (el.getprevious().attrib['data-lon-offset'] > el.attrib['data-lon-offset'] or (el.getprevious().attrib['data-lon-offset'] == el.attrib['data-lon-offset'] and last_state == 'up')): print('up') - rot_el = el[0][0][0] - # print(rot_el.attrib['data-image-rotation']) - # print(rot_el.attrib['data-image-dimensions']) + rot_el = el[0][0] el.attrib['data-direction'] = 'up' - - # print(el.attrib['data-lat'], el.getprevious().attrib['data-lat']) else: - rot_el = el[0][0][0] + rot_el = el[0][0] el.attrib['data-direction'] = 'down' - # el.attrib['style'] = 'opacity:0' - new_rotation = image_rotation_down #float(rot_el.attrib['data-image-rotation']) + 180 - rot_el.attrib['transform'] = "rotate({} {})".format(str(new_rotation), rot_el.attrib['data-image-dimensions']) print('down') - # print(rot_el.attrib['data-image-rotation']) - # print(rot_el.attrib['data-image-dimensions']) + # NOT NEEDED SINCE THERE IS A ROTATION INFORMATION # merge tiles into groups - print(index) - print("el.attrib['data-direction'] " + el.attrib['data-direction']) - print("last_state " + last_state) - if index is 1 or last_state != el.attrib['data-direction']: + # print(index) + # print("el.attrib['data-direction'] " + el.attrib['data-direction']) + # print("last_state " + last_state) + if index is 1 or last_state is not el.attrib['data-direction']: current_row = ET.SubElement(tile_rows, 'g', attrib={ 'class': 'tile-row' }) copyElem = copy.deepcopy(el) current_row.insert(0, copyElem) last_state = el.attrib['data-direction'] +# remove temporary group root.remove(main_layer) +# resize canvas to tiles and add some padding -with open(os.path.join(working_dir,'map.svg'), 'wb') as f: - tree.write(f, encoding='utf-8') +print(width, height, args.scale) +scaled_width = width * args.scale +scaled_height = height * args.scale + +padding = 500 + +canvas_width = str(scaled_width + padding*2) +canvas_height = str(scaled_height + padding*2) +viewbox_x = str(padding * -1) +viewbox_y = str((scaled_height + padding) * -1) +viewbox_width = canvas_width +viewbox_height = canvas_height -# # get some base satellite map for reference -# apikey = "MYaMHCLtPz1fUfe0FzZqOMI35m893jIV80oeHG19Piw" -# lon_center = -# lat_center = -# zoom = -# map_width = -# request = "https://image.maps.ls.hereapi.com/mia/1.6/mapview?apiKey={}&c={},{}&sb=mk&t=1&z={}&w={}&nodot".format(apikey, lon_center, lat_center, zoom, map_width) +root.attrib['width'] = canvas_width +root.attrib['height'] = canvas_height +root.attrib['viewBox'] = "{} {} {} {}".format(viewbox_x, viewbox_y, viewbox_width, viewbox_height) + + + +# Finally save the svg +with open(OUTPUT_PATH, 'wb') as f: + tree.write(f, encoding='utf-8') -# svg = ET.tostring(tree, encoding="unicode") -# print(svg) print('Done!') + +