diff --git a/lib/xcsoar/mapgen/server/server.py b/lib/xcsoar/mapgen/server/server.py index 94666b3..dd28d8b 100644 --- a/lib/xcsoar/mapgen/server/server.py +++ b/lib/xcsoar/mapgen/server/server.py @@ -91,12 +91,25 @@ def index(self, **params): waypoint_file.filename ) ) + + if not filename.endswith(".dat") and not filename.endswith(".cup"): + raise RuntimeError( + "Waypoint file {} has an unsupported format.".format( + waypoint_file.filename + ) + ) + desc.bounds = parse_waypoint_file( waypoint_file.filename, waypoint_file.file ).get_bounds() desc.waypoint_file = ( "waypoints.cup" if filename.endswith(".cup") else "waypoints.dat" ) + + return view.render( + error=f"left: {desc.bounds.left:.3f}, right: {desc.bounds.right:.3f}, top: {desc.bounds.top:.3f}, bot {desc.bounds.bottom:.3f}" + ) | HTMLFormFiller(data=params) + except: return view.render( error="Unsupported waypoint file " + waypoint_file.filename @@ -134,6 +147,7 @@ def index(self, **params): if desc.waypoint_file: waypoint_file.file.seek(0) + f = open(job.file_path(desc.waypoint_file), "w") try: shutil.copyfileobj(fsrc=waypoint_file.file, fdst=f, length=1024 * 64) diff --git a/lib/xcsoar/mapgen/server/view.py b/lib/xcsoar/mapgen/server/view.py index a34bc54..4269db6 100644 --- a/lib/xcsoar/mapgen/server/view.py +++ b/lib/xcsoar/mapgen/server/view.py @@ -41,6 +41,7 @@ def render(*args, **kwargs): template = loader.load(args[0]) else: template = cherrypy.thread_data.template + ctxt = Context(url=cherrypy.url) ctxt.push(kwargs) return template.generate(ctxt) diff --git a/lib/xcsoar/mapgen/waypoints/list.py b/lib/xcsoar/mapgen/waypoints/list.py index 9b9cf9c..16de5a4 100644 --- a/lib/xcsoar/mapgen/waypoints/list.py +++ b/lib/xcsoar/mapgen/waypoints/list.py @@ -39,4 +39,5 @@ def get_bounds(self, offset_distance=15.0): rc.bottom = min(rc.bottom, wp.lat) rc.expand(offset_distance) + return rc diff --git a/lib/xcsoar/mapgen/waypoints/parser.py b/lib/xcsoar/mapgen/waypoints/parser.py index 387a74f..55aaa3d 100644 --- a/lib/xcsoar/mapgen/waypoints/parser.py +++ b/lib/xcsoar/mapgen/waypoints/parser.py @@ -3,14 +3,13 @@ from xcsoar.mapgen.waypoints.winpilot_reader import parse_winpilot_waypoints -def parse_waypoint_file(filename, file=None): - if not file: - file = open(filename, "r") +def parse_waypoint_file(filename, file): + lines = file.readlines() if filename.lower().endswith(".xcw") or filename.lower().endswith(".dat"): - return parse_winpilot_waypoints(file) + return parse_winpilot_waypoints(lines) elif filename.lower().endswith(".cup"): - return parse_seeyou_waypoints(file) + return parse_seeyou_waypoints(lines) # 241207 gfp bugfix: else: raise RuntimeError( "Waypoint file {} has an unsupported format.".format(filename) diff --git a/lib/xcsoar/mapgen/waypoints/seeyou_reader.py b/lib/xcsoar/mapgen/waypoints/seeyou_reader.py index f69564a..2888773 100644 --- a/lib/xcsoar/mapgen/waypoints/seeyou_reader.py +++ b/lib/xcsoar/mapgen/waypoints/seeyou_reader.py @@ -76,26 +76,34 @@ def __parse_length(str): def parse_seeyou_waypoints(lines, bounds=None): waypoint_list = WaypointList() - first = True - for line in lines: - if first: - first = False - continue - - line = line.strip() - if line == "name,code,country,lat,lon,elev,style,rwdir,rwlen,freq,desc": - continue - + header = "name,code,country,lat,lon,elev,style,rwdir,rwlen,freq,desc" + + wpnum = 0 + for byteline in lines: + wpnum = wpnum + 1 + try: + line = byteline.decode("UTF-8") + except UnicodeDecodeError as e: + raise RuntimeError( + f"Failed to decode line {wpnum} as UTF-8: {e}. " + f"Please check the waypoint file encoding and fix any corrupted data." + ) from e + + # check for blank lines or comments if line == "" or line.startswith("*"): continue + if header in line: + continue # skip to next line (first waypoint line) + if line == "-----Related Tasks-----": break fields = [] - line = __CSVLine(line) - while line.has_next(): - fields.append(next(line)) + CSVline = __CSVLine(line) + + while CSVline.has_next(): + fields.append(next(CSVline)) if len(fields) < 6: continue diff --git a/lib/xcsoar/mapgen/waypoints/winpilot_reader.py b/lib/xcsoar/mapgen/waypoints/winpilot_reader.py index 50abd4b..b1294a5 100644 --- a/lib/xcsoar/mapgen/waypoints/winpilot_reader.py +++ b/lib/xcsoar/mapgen/waypoints/winpilot_reader.py @@ -10,23 +10,33 @@ def __parse_altitude(str): return int(str) * 0.3048 else: str = str.rstrip("m") - return int(str) + float_alt = float(str) + int_alt = int(float_alt) + return int(int_alt) + +# Winpilot .DAT file lat/lon formats +# Latitude, Longitude: in one of the following formats (ss=seconds, dd = decimals): +# dd:mm:ss (for example: 36:15:20N) +# dd:mm.d (for example: 36:15.3N) +# dd:mm.dd (for example: 36:15.33N) +# dd:mm.ddd (for example: 36:15.333N) def __parse_coordinate(str): + str = str.lower() negative = str.endswith("s") or str.endswith("w") str = str.rstrip("sw") if negative else str.rstrip("ne") - str = str.split(":") - if len(str) < 2: + strsplit = str.split(":") + if len(strsplit) < 2: return None - if len(str) == 2: + if len(strsplit) == 2: # degrees + minutes / 60 - a = int(str[0]) + float(str[1]) / 60 + a = int(strsplit[0]) + float(strsplit[1]) / 60 - if len(str) == 3: + if len(strsplit) == 3: # degrees + minutes / 60 + seconds / 3600 a = int(str[0]) + float(str[1]) / 60 + float(str[2]) / 3600 @@ -37,8 +47,11 @@ def __parse_coordinate(str): def parse_winpilot_waypoints(lines): waypoint_list = WaypointList() + wpnum = 0 + for byteline in lines: + wpnum += 1 - for line in lines: + line = byteline.decode("UTF-8") line = line.strip() if line == "" or line.startswith("*"): continue