From 5df1ea3acad3ca2be37abe668aa3a0c00625354c Mon Sep 17 00:00:00 2001 From: TheFGFSEagle Date: Mon, 28 Feb 2022 17:11:21 +0100 Subject: [PATCH] Move scenery tools into their own folder, added STG to UFO XML configuration file converter and begins of a JavaProp to JSBsim CP and CT table converter --- aircraft/javaprop2jsbcpct.py | 29 ++++++ edit-stg.py => scenery/edit-stg.py | 0 scenery/stg2ufo.py | 155 +++++++++++++++++++++++++++++ 3 files changed, 184 insertions(+) create mode 100644 aircraft/javaprop2jsbcpct.py rename edit-stg.py => scenery/edit-stg.py (100%) create mode 100755 scenery/stg2ufo.py diff --git a/aircraft/javaprop2jsbcpct.py b/aircraft/javaprop2jsbcpct.py new file mode 100644 index 0000000..f256245 --- /dev/null +++ b/aircraft/javaprop2jsbcpct.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python +#-*- coding:utf-8 -*- + +import argparse + +if __name__ == "__main__": + argp = argparse.ArgumentParser(description="javaprop2jsbcpct.py - converts JavaProp propeller data into Cp and Ct tables for a JSBsim propelller") + + argp.add_argument( + "-i", "--input-file", + help="File to read JavaProp data from", + ) + + argp.add_argument( + "--interactive", + help="Read JavaProp data from standard input instead of a file, ignoring --input-file (disabled by default)", + nargs=0 + type=bool, + default=False + ) + + argp.add_argument( + "--indentation", + help="Indentation to use (the argument of this option will be used as one level of indentation), defaults to tabs", + default="\t" + ) + + args = argp.parse_args() + print(args) diff --git a/edit-stg.py b/scenery/edit-stg.py similarity index 100% rename from edit-stg.py rename to scenery/edit-stg.py diff --git a/scenery/stg2ufo.py b/scenery/stg2ufo.py new file mode 100755 index 0000000..46cb2c5 --- /dev/null +++ b/scenery/stg2ufo.py @@ -0,0 +1,155 @@ +#!/usr/bin/env python3 +#-*- coding:utf-8 -*- + +import argparse +import os + +class SkipReason: + NotFound = 0 + DirEmpty = 1 + NoSTG = 2 + +def read_stg_file(path): + result = [] + offset = 0 + skipnext = False + with open(path, "r") as fp: + content = fp.readlines() + for number, line in enumerate(content): + line = line.strip() + if line.startswith("#"): # is a comment + if line.startswith("# offset"): + offset = line.split(" ")[-1] + result.append(line) + elif line.startswith("# skipnext"): + skipnext = True + elif line.strip() == "": # empty line + continue + else: # is an object + etype, *data = list(map(lambda s: s.strip(), line.split(" "))) + if etype in ["OBJECT_SHARED", "OBJECT_STATIC"]: + if len(data) == 5: + objectfile, longitude, latitude, elevation, heading, pitch, roll = *data, 0, 0 + elif len(data) == 7: + objectfile, longitude, latitude, elevation, heading, pitch, roll = data + else: + print(f"Warning: file {path}, line {number} is malformed - not converting entry") + result.append(line) + continue + + result.append({ + "etype": etype, + "objectfile": objectfile, + "longitude": longitude, + "latitude": latitude, + "elevation": float(elevation), + "offset": float(offset), + "heading": heading, + "pitch": pitch, + "roll": roll, + "skip": skipnext + }) + offset = 0 + skipnext = False + else: + print(f"Warning: skipping line {number} in {path} because type {etype} is not supported") + return result + +def read_stg_files(paths): + stg_dict = dict.fromkeys(paths, {"infiles": [], "contents": []}) + for path in paths: + if not os.path.exists(path): + print(f"Warning: Input file / directory {path} does not exist, skipping") + stg_dict[path] = SkipReason.NotFound + elif os.path.isdir(path): + for file in os.listdir(path): + if os.splitext(path)[1] == ".stg": + realpath = os.path.join(path, file) + content = read_stg_file(realpath) + stg_dict[path]["infiles"].append(file) + stg_dict[path]["contents"].append(content) + else: + print(f"Warning: No STG file found in input directory {path}, skipping") + stg_dict[path] = SkipReason.DirEmpty + else: + if os.path.splitext(path)[1] == ".stg": + content = read_stg_file(path) + stg_dict[path]["infiles"].append(path) + stg_dict[path]["contents"].append(content) + else: + print(f"Warning: Input file {path} is not an STG file, skipping") + stg_dict[path] = SkipReason.NoSTG + return stg_dict + +def write_xml_files(output_stg, outfiles): + for i, path in enumerate(output_stg): + if type(path) != str: # SkipReason + continue + for infile, content in zip(output_stg[path]["infiles"], output_stg[path]["contents"]): + if len(outfiles) == 1: + if outfiles[0] == "__INPUT__": + outfile = infile + else: + outfile = outfiles[0] + else: + if i < len(outfiles): + outfile = outfiles[i] + else: + outfile = outfiles[-1] + + with open(outfile, "w") as outfp: + outfp.write("\n") + outfp.write("\n") + outfp.write(" \n") + + for object in content: + outfp.write(" \n") + outfp.write(f" {object['objectfile'].split('/')[-1]}\n") + outfp.write(f" {object['pitch']}\n") + outfp.write(f" {object['pitch']}\n") + outfp.write(f" {object['heading']}\n") + outfp.write(f" {object['latitude']}\n") + outfp.write(f" {object['longitude']}\n") + outfp.write(f" {float(object['elevation']) * 3.2808399}\n") + outfp.write(f" {object['elevation']}\n") + outfp.write(f" {float(object['heading']) + 180}\n") + outfp.write(f" {os.path.abspath(path)}\n") + + objectpath = object["objectfile"] + if object["etype"] == "OBJECT_STATIC": + objectpath = path + "/" + objectpath + outfp.write(f" {objectpath}\n") + + line = f"{object['etype']} {object['objectfile']} {object['longitude']} {object['latitude']} {object['elevation'] + object['offset']} {object['heading']} {object['pitch']} {object['roll']}" + outfp.write(f" {line}\n") + outfp.write(" \n") + + outfp.write(" \n") + outfp.write("\n") + +def main(): + argp = argparse.ArgumentParser(description="Perform various STG file operations such as recalculating the elevation of models") + + argp.add_argument( + "-i", "--input", + help="Input STG file. Mandatory, more than one file / directory can be passed", + nargs="+", + required=True + ) + + argp.add_argument( + "-o", "--output", + help="Output STG file. Default is to overwrite the input file(s).", + nargs="+", + default=["__INPUT__"] + ) + + args = argp.parse_args() + infiles = args.input + outfiles = args.output + + input_stg = read_stg_files(infiles) + exitstatus = write_xml_files(input_stg, outfiles) + +if __name__ == "__main__": + main()