app.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. import uuid
  2. import os
  3. import zipfile
  4. import shutil
  5. import sys
  6. import urllib.request
  7. import gzip
  8. from flask import Flask
  9. from flask import render_template
  10. from flask import request
  11. from terrain_gen import add_offset
  12. # The output folder for all gzipped terrain requests
  13. app = Flask(__name__, static_url_path='/terrain', static_folder='outputTer',)
  14. def clamp(n, smallest, largest):
  15. return max(smallest, min(n, largest))
  16. def getDatFile(lat, lon):
  17. '''Get file'''
  18. if lat < 0:
  19. NS = 'S'
  20. else:
  21. NS = 'N'
  22. if lon < 0:
  23. EW = 'W'
  24. else:
  25. EW = 'E'
  26. return "%c%02u%c%03u.DAT.gz" % (NS, min(abs(int(lat)), 99), EW, min(abs(int(lon)), 999))
  27. def compressFiles(fileList, uuidkey, outfolder):
  28. # create a zip file comprised of dat.gz tiles
  29. zipthis = os.path.join(os.getcwd(), outfolder, uuidkey + '.zip')
  30. foldertmp = os.path.join(os.getcwd(), outfolder + "-tmp", uuidkey)
  31. # create tmp and output dirs if needed
  32. os.makedirs(foldertmp)
  33. try:
  34. os.makedirs(os.path.join(os.getcwd(), outfolder))
  35. except OSError:
  36. pass
  37. try:
  38. with zipfile.ZipFile(zipthis, 'w') as terrain_zip:
  39. for fn in fileList:
  40. if not os.path.exists(fn):
  41. #download if required
  42. g = urllib.request.urlopen('https://firmware.ardupilot.org/terrain/terraingen/processedTerrain/' + os.path.basename(fn))
  43. print("Downloaded " + os.path.basename(fn))
  44. with open(fn, 'b+w') as f:
  45. f.write(g.read())
  46. # need to decompress file
  47. datfile = os.path.join(foldertmp, os.path.basename(fn)[:-3])
  48. with gzip.open(fn, 'r') as f_in, open(datfile, 'wb') as f_out:
  49. shutil.copyfileobj(f_in, f_out)
  50. print("Decomp " + os.path.basename(fn))
  51. # and add file to zip
  52. terrain_zip.write(datfile, os.path.basename(datfile), compress_type = zipfile.ZIP_DEFLATED)
  53. # remove cache (decompressed files)
  54. shutil.rmtree(foldertmp)
  55. except Exception as ex:
  56. print("Unexpected error: {0}".format(ex))
  57. return False
  58. #terrain_zip.close()
  59. return True
  60. @app.route('/')
  61. def index():
  62. return render_template('index.html')
  63. @app.route('/generate', methods=['GET', 'POST'])
  64. def generate():
  65. if request.method == 'POST':
  66. # parse and sanitise the input
  67. try:
  68. # request.form['username']
  69. lat = float(request.form['lat'])
  70. lon = float(request.form['long'])
  71. radius = int(request.form['radius'])
  72. assert lat < 90
  73. assert lon < 180
  74. assert lat > -90
  75. assert lon > -180
  76. radius = clamp(radius, 1, 400)
  77. except:
  78. print("Bad data")
  79. return render_template('generate.html', error = "Error with input")
  80. # UUID for this terrain generation
  81. uuidkey = str(uuid.uuid1())
  82. # Flag for if user wanted a tile outside +-60deg latitude
  83. outsideLat = None
  84. # get a list of files required to cover area
  85. filelist = []
  86. done = set()
  87. for dx in range(-radius, radius):
  88. for dy in range(-radius, radius):
  89. (lat2, lon2) = add_offset(lat*1e7, lon*1e7, dx*1000.0, dy*1000.0)
  90. lat_int = int(round(lat2 * 1.0e-7))
  91. lon_int = int(round(lon2 * 1.0e-7))
  92. tag = (lat_int, lon_int)
  93. if tag in done:
  94. continue
  95. done.add(tag)
  96. # make sure tile is inside the 60deg latitude limit
  97. if (abs(lat_int) < 60):
  98. filelist.append(os.path.join(os.getcwd(), "processedTerrain", getDatFile(lat_int, lon_int)))
  99. else:
  100. outsideLat = True
  101. # make sure tile is inside the 60deg latitude limit
  102. if (abs(lat_int) < 60):
  103. filelist.append(os.path.join(os.getcwd(), "processedTerrain", getDatFile(lat_int, lon_int)))
  104. else:
  105. outsideLat = True
  106. # remove duplicates
  107. filelist = list(dict.fromkeys(filelist))
  108. print(filelist)
  109. #compress
  110. success = compressFiles(filelist, uuidkey, 'outputTer')
  111. if success:
  112. print("Generated " + "/terrain/" + uuidkey + ".zip")
  113. return render_template('generate.html', urlkey="/terrain/" + uuidkey + ".zip", uuidkey=uuidkey, outsideLat=outsideLat)
  114. else:
  115. print("Failed " + "/terrain/" + uuidkey + ".zip")
  116. return render_template('generate.html', error="Cannot generate terrain", uuidkey=uuidkey)
  117. else:
  118. print("Bad get")
  119. return render_template('generate.html', error="Need to use POST, not GET")