#! /usr/bin/python3 # Copyright (C) 2018-2019 Merspieler, merspieler _at_ airmail.cc # # 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, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. import sys import os import re from math import ceil import time import traceback argc = len(sys.argv) i = 1 first = 1 create_zip = False build_all = True build_fix = False build_continue = False man_threads = "" project = "" chunk_size = 1 while i < argc: if sys.argv[i] == "-t" or sys.argv[i] == "--threads": i += 1 man_threads = "-t " + sys.argv[i] elif sys.argv[i] == "-z" or sys.argv[i] == "--zip": create_zip = True elif sys.argv[i] == "-c" or sys.argv[i] == "--continue": build_all = False build_continue = True elif sys.argv[i] == "-f" or sys.argv[i] == "--fix": build_all = False build_fix = True elif sys.argv[i] == "-S" or sys.argv[i] == "--chunk-size": i += 1 chunk_size = int(sys.argv[i]) elif sys.argv[i] == "-h" or sys.argv[i] == "--help": print("usage: build [OPTIONS]") print("Builds the tiles with osm2city") print("") print("OPTIONS") print(" -h, --help Shows this help and exit") print(" -t, --threads Number of threads used for building") print(" This will overwrite the value from the general-settings file") print(" -z, --zip Create a ready to distribute zip file on success") print(" -S, --chunk-size Chunks in which the scenery is build.") print(" Smaller numbers allow better continuation on interruption") print("") print(" -c, --continue Continue interrupted build") print(" -f, --fix Try to rebuild tiles wich had exceptions in the previous run") sys.exit(0) else: if first == 1: first = 0 project = sys.argv[i] else: print("Unknown option " + sys.argv[i]) sys.exit(1) i += 1 if project == "": print("No project was given. See build -h for details") sys.exit(1) # Takes a file as input and returns a list of bounds def get_bounds(file_path): try: with open(file_path) as f: hits = [] lines = f.readlines() for line in lines: match = re.findall("(-?[0-9]{1,3}\.?[0-9]{0,4})_(-?[0-9]{1,2}\.?[0-9]{0,4})_(-?[0-9]{1,3}\.?[0-9]{0,4})_(-?[0-9]{1,2}\.?[0-9]{0,4})", line) if match != []: bounds = { "west": float(match[0][0]), "south": float(match[0][1]), "east": float(match[0][2]), "north": float(match[0][3]) } hits.append(bounds) # Filter duplicates ret = [] ret.append(hits[0]) for hit in hits: duplicate = False for coords in ret: if coords == hit: duplicate = True if not duplicate: ret.append(coords) return ret except: print("WARNING: Getting bounds from '" + file_path + "' failed") sys.exit(1) def run_build(west, south, east, north, log_done=False, start_w=None, start_s=None, chunk_size=1): width = ceil(east - west) height = ceil(north - south) if start_w != None and start_s != None: start_offset = True s = ceil(north - start_s) w = ceil(east - start_w) # Case most east tile has been build last if w == width: w = 0 s += 1 else: start_offset = False w = 0 s = 0 while w < width: build_w = west + w build_e = build_w + chunk_size if build_e > east: build_e = east if build_w < 0: build_w = "*" + str(build_w) if start_offset: start_offset = False else: s = 0 while s < height: build_s = south + s build_n = build_s + chunk_size if build_n > north: build_n = north run_command("bash build_tile " + project + " " + man_threads + " -b " + str(build_w) + "_" + str(build_s) + "_" + str(build_e) + "_" + str(build_n)) if log_done: try: f = open("projects/" + project + "/done", "w") f.write(str(build_w) + "_" + str(build_s) + "_" + str(build_e) + "_" + str(build_n)) f.close() except: print("WARNING: Writing done file failed") s += chunk_size w += chunk_size def run_command(command): exit_code = os.system(command) if exit_code == 0: return elif exit_code == 1: print("An argument problem occured while running '" + command + "'") sys.exit(1) elif exit_code == 130: print("Interrupted by user. Aborting...") sys.exit(130) start_time = time.time() try: if build_all: bounds = get_bounds("projects/" + project + "/settings") run_command("rm -f projects/" + project + "/osm2city-exceptions.log") run_build(bounds[0]["west"], bounds[0]["south"], bounds[0]["east"], bounds[0]["north"], log_done=True, chunk_size=chunk_size) else: if build_fix: bounds = get_bounds("projects/" + project + "/osm2city-exceptions.log") run_command("rm -f projects/" + project + "/osm2city-exceptions.log") if bounds == []: print("INFO: Skip fix run: no exceptions found") else: for area in bounds: run_build(area["west"], area["south"], area["east"], area["north"]) if build_continue: start_bounds = get_bounds("projects/" + project + "/done") if start_bounds == []: print("No start bounds found. Please rerun without -c") sys.exit(1) project_bounds = get_bounds("projects/" + project + "/settings") if project_bounds == []: print("Unable to read project settings") sys.exit(2) start_bounds = start_bounds[0] project_bounds = project_bounds[0] chunks = start_bounds["east"] - start_bounds["west"] if start_bounds["north"] == project_bounds["north"] and start_bounds["east"] == project_bounds["east"]: print("It seems like the project build is complete. If you wish to rerun please do so without -c") else: run_build(project_bounds["west"], project_bounds["south"], project_bounds["east"], project_bounds["north"], log_done=True, start_w=start_bounds["east"], start_s=start_bounds["south"], chunk_size=chunks) except KeyboardInterrupt: print("Interrupted by user!") sys.exit(130) except Exception as err: print("An unknown error occurred!") traceback.print_tb(err.__traceback__) sys.exit(4) # Get build time end_time = time.time() elapsed = end_time - start_time seconds = elapsed % 60 elapsed = (elapsed - seconds) / 60 minutes = elapsed % 60 elapsed = (elapsed - minutes) / 60 hours = elapsed % 24 days = (elapsed - hours) / 24 time = str(int(hours)) + " Hours, " + str(int(minutes)) + " Minutes and " + str(int(seconds)) + " Seconds" if days > 0: time = str(int(days)) + " Days, " + time print("Building " + project + " took " + time) if os.path.isfile("projects/" + project + "/osm2city-exceptions.log"): print("There have been exceptionss in the build.") print("Please check the osm2city-exceptions.log") print("If you want to rebuild only failed tiles, run with the -f parameter") elif create_zip == True: print("Creating zip file...") run_command("zip -rq projects/" + project + "/" + project + ".zip projects/" + project + "/scenery/")