|
|
|
|
@ -2,15 +2,19 @@ import argparse
|
|
|
|
|
import csv |
|
|
|
|
import os.path as path |
|
|
|
|
import re |
|
|
|
|
import constants.fields as F |
|
|
|
|
|
|
|
|
|
importdir = 'images' |
|
|
|
|
datafile = path.join(importdir, 'gps.csv') |
|
|
|
|
args = None |
|
|
|
|
|
|
|
|
|
# Imported data with appended attributes as list of lists |
|
|
|
|
# Items: |
|
|
|
|
# Based on imported CSV and added with attributes: |
|
|
|
|
# data with appended attributes as list of lists. |
|
|
|
|
# Items ---> See constants/fields.py <--- |
|
|
|
|
# - ID |
|
|
|
|
# - Image file name |
|
|
|
|
# - lon, lat |
|
|
|
|
# - lon |
|
|
|
|
# - lat |
|
|
|
|
# - title, description |
|
|
|
|
# - x, y: Default tile position |
|
|
|
|
data = None |
|
|
|
|
@ -47,8 +51,15 @@ def exit_with_error(message):
|
|
|
|
|
|
|
|
|
|
def read_csv_to_dict(csv_file): |
|
|
|
|
""" |
|
|
|
|
Reads a CSV file and returns a list of dictionaries, one per row. |
|
|
|
|
Assumes the first row contains headers. |
|
|
|
|
Reads a tab-separated CSV file and returns a list of dictionaries, one per row |
|
|
|
|
in the full data item size. Placeholder for unfilled fields is None. |
|
|
|
|
Fields: |
|
|
|
|
0: ID (integer), ascending starting with '1' <-- not in CSV |
|
|
|
|
1: image file name (string) |
|
|
|
|
2: latitude and longitude (floats), separated by space. |
|
|
|
|
3. title (string) |
|
|
|
|
4. description (string) |
|
|
|
|
The items must be sorted chronologically. Assumes the first row contains headers. |
|
|
|
|
In error case, returns None |
|
|
|
|
""" |
|
|
|
|
global message |
|
|
|
|
@ -57,6 +68,7 @@ def read_csv_to_dict(csv_file):
|
|
|
|
|
reader = csv.reader(f, skipinitialspace=False, delimiter='\t') |
|
|
|
|
log(f"Read lines from {csv_file}") |
|
|
|
|
|
|
|
|
|
id = 0 |
|
|
|
|
for row in reader: |
|
|
|
|
|
|
|
|
|
logvv(f"Processing row: {row}") |
|
|
|
|
@ -74,9 +86,21 @@ def read_csv_to_dict(csv_file):
|
|
|
|
|
if len(geo) != 2: |
|
|
|
|
message = f'Invalid loc/lon: {row[1]}' |
|
|
|
|
|
|
|
|
|
values = [ row[0], float(geo[0]), float(geo[1]), row[2], row[3] ] |
|
|
|
|
id += 1 |
|
|
|
|
# Order and size must match constants.fields |
|
|
|
|
# values = [id, row[0], float(geo[0]), float(geo[1]), row[2], row[3] ] |
|
|
|
|
values = [] |
|
|
|
|
values.insert(F.ID, id) |
|
|
|
|
values.insert(F.FILE, row[0]) |
|
|
|
|
values.insert(F.LON, float(geo[0])) |
|
|
|
|
values.insert(F.LAT, float(geo[1])) |
|
|
|
|
values.insert(F.TITLE, row[2]) |
|
|
|
|
values.insert(F.DESCRIPTION, row[3]) |
|
|
|
|
values.insert(F.POSX, None) |
|
|
|
|
values.insert(F.POSY, None) |
|
|
|
|
data.append(values) |
|
|
|
|
logvv(f"Read row : {values}") |
|
|
|
|
|
|
|
|
|
logvv(f"Processed item : {values}") |
|
|
|
|
|
|
|
|
|
if len(data) == 0: |
|
|
|
|
message = f'Empty file: {csv_file}' |
|
|
|
|
@ -117,18 +141,18 @@ def find_geo_extrema(data):
|
|
|
|
|
if len(data) == 0: |
|
|
|
|
return None |
|
|
|
|
|
|
|
|
|
lonmin = lonmax = data[0][1] |
|
|
|
|
latmin = latmax = data[0][2] |
|
|
|
|
lonmin = lonmax = data[0][F.LON] |
|
|
|
|
latmin = latmax = data[0][F.LAT] |
|
|
|
|
|
|
|
|
|
for entry in data[1:]: |
|
|
|
|
if entry[1] < lonmin: |
|
|
|
|
lonmin = entry[1] |
|
|
|
|
if entry[1] > lonmax: |
|
|
|
|
lonmax = entry[1] |
|
|
|
|
if entry[2] < latmin: |
|
|
|
|
latmin = entry[2] |
|
|
|
|
if entry[2] > latmax: |
|
|
|
|
latmax = entry[2] |
|
|
|
|
if entry[F.LON] < lonmin: |
|
|
|
|
lonmin = entry[F.LON] |
|
|
|
|
if entry[F.LON] > lonmax: |
|
|
|
|
lonmax = entry[F.LON] |
|
|
|
|
if entry[F.LAT] < latmin: |
|
|
|
|
latmin = entry[F.LAT] |
|
|
|
|
if entry[F.LAT] > latmax: |
|
|
|
|
latmax = entry[F.LAT] |
|
|
|
|
|
|
|
|
|
return (lonmin, lonmax, latmin, latmax) |
|
|
|
|
|
|
|
|
|
@ -138,6 +162,7 @@ def translate_pos(min, max, pos, size):
|
|
|
|
|
|
|
|
|
|
return round((pos - min) / (max - min) * size) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def append_tile_pos(data, geo_extrema, matrixdims): |
|
|
|
|
""" |
|
|
|
|
Adds two columns with x and y position (integer) of the tile in the canvas |
|
|
|
|
@ -157,10 +182,73 @@ def append_tile_pos(data, geo_extrema, matrixdims):
|
|
|
|
|
|
|
|
|
|
return ret |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def create_playbook(data): |
|
|
|
|
""" |
|
|
|
|
Returns list of dict [delta1, delta2, ...] with changes (in both direections) for every single tour. |
|
|
|
|
The snapshot holds the complete canvas for the actual step. The playbook contains exclusively |
|
|
|
|
changed values (delta). |
|
|
|
|
Rules to process: |
|
|
|
|
- Loop over all n data items: start with the first (oldest) item (0) |
|
|
|
|
- Copy previous snapshot (to find changes in a later step) |
|
|
|
|
- Run recursively over the the snapshot items: Find an existing item at the position |
|
|
|
|
of the actual image and change its position by the displacement rule. |
|
|
|
|
- Place the image of the actual item (a) at its default position in the snapshot |
|
|
|
|
- Create a item for the following image (a+1) and hide it (for scrolling backwards). |
|
|
|
|
- Store all changes betweeen snapshot and previous snapshot in a new delta (a) and append it |
|
|
|
|
to the return dict. |
|
|
|
|
In error case, None will be returned. |
|
|
|
|
""" |
|
|
|
|
|
|
|
|
|
snapshot = prev_snapshot = [] |
|
|
|
|
ret = [] |
|
|
|
|
|
|
|
|
|
for a in data: |
|
|
|
|
prev_snapshot = snapshot |
|
|
|
|
|
|
|
|
|
(x, y) = (a[F.POSX], a[F.POSY]) |
|
|
|
|
|
|
|
|
|
snapshot = shifting_snapshot_items(x,y, snapshot) |
|
|
|
|
|
|
|
|
|
return ret |
|
|
|
|
|
|
|
|
|
def shifting_snapshot_items(x, y, snapshot): |
|
|
|
|
""" |
|
|
|
|
Recursive change item chain starting with item at position x,y. |
|
|
|
|
Returns updated snapshot |
|
|
|
|
""" |
|
|
|
|
|
|
|
|
|
goon = True |
|
|
|
|
(actx, acty) = (x, y) |
|
|
|
|
ret = snapshot |
|
|
|
|
|
|
|
|
|
while goon: |
|
|
|
|
goon = False |
|
|
|
|
for i, item in enumerate(ret): |
|
|
|
|
if (item[F.POSX], item[F.POSY]) == (actx, acty): |
|
|
|
|
# ret[i][F.POSX], ret[i][F.POSY] = |
|
|
|
|
goon = True |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return ret |
|
|
|
|
|
|
|
|
|
def shifting(tup, matrixdims): |
|
|
|
|
"""Strategy to shift. Above and on the horizontal middle line, the position |
|
|
|
|
will be shifted to the top. Positions below the horizontal middle line, |
|
|
|
|
the position will be shifted in bottom direction. |
|
|
|
|
Returns the offset as (x, y) tuple, not the new position itself. |
|
|
|
|
""" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def calculate_orig_pos(): |
|
|
|
|
global data |
|
|
|
|
geo_extrema = find_geo_extrema(data) |
|
|
|
|
data = append_tile_pos(data, geo_extrema, matrixdims) |
|
|
|
|
playbook = create_playbook(data) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def main(): |
|
|
|
|
|