app.py 4.7 KB

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