Initial commit
This commit is contained in:
		
						commit
						a647d26337
					
				
					 21 changed files with 4707 additions and 0 deletions
				
			
		
							
								
								
									
										10
									
								
								.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,10 @@ | ||||||
|  | /target | ||||||
|  | /dist | ||||||
|  | /build | ||||||
|  | **/*.rs.bk | ||||||
|  | *.tmp | ||||||
|  | *.idx | ||||||
|  | .vscode/** | ||||||
|  | build.bat | ||||||
|  | test.bat | ||||||
|  | __pycache__ | ||||||
							
								
								
									
										2
									
								
								MANIFEST.in
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								MANIFEST.in
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,2 @@ | ||||||
|  | include rust/Cargo.toml | ||||||
|  | recursive-include rust/src * | ||||||
							
								
								
									
										43
									
								
								README.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								README.md
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,43 @@ | ||||||
|  | # Testing | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | conda create -n ed_lrr_gui_env python=3 | ||||||
|  | conda activate ed_lrr_gui_env | ||||||
|  | python build_gui.py | ||||||
|  | pip install -e . | ||||||
|  | rs_gui_test | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | # Building | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | conda create -n ed_lrr_gui_env python=3 | ||||||
|  | conda activate ed_lrr_gui_env | ||||||
|  | python build_gui.py | ||||||
|  | python build_gui.py | ||||||
|  | python build_gui.py | ||||||
|  | pip install setuptools_rust | ||||||
|  | pip install . | ||||||
|  | python setup.py build | ||||||
|  | python setup.py bdist_wheel | ||||||
|  | python setup.py sdist | ||||||
|  | mkdir exe | ||||||
|  | cd exe | ||||||
|  | pyinstaller --noupx --name ed_lrr_gui ../ed_lrr_gui/__main__.py | ||||||
|  | pyinstaller --noupx --onefile --name ed_lrr_gui ../ed_lrr_gui/__main__.py | ||||||
|  | cd .. | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | # Clean | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | rm -rfv _*.pyd *.pyc *.egg-info pip-wheel-metadata dist exe build __pycache__ | ||||||
|  | cd rust | ||||||
|  | cargo clean | ||||||
|  | cargo clean --release | ||||||
|  | cd .. | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | # TODO | ||||||
|  | - refactor ed_lrr to use callbacks | ||||||
|  | - integrate callbacks into the GUI | ||||||
							
								
								
									
										13
									
								
								build_gui.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								build_gui.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,13 @@ | ||||||
|  | import subprocess as SP | ||||||
|  | from glob import glob | ||||||
|  | import os | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ui_path = os.path.dirname(os.path.abspath(__file__)) | ||||||
|  | for root, folders, files in os.walk(ui_path): | ||||||
|  |     for file in files: | ||||||
|  |         file = os.path.join(root, file) | ||||||
|  |         outfile, ext = os.path.splitext(file) | ||||||
|  |         if ext == ".ui": | ||||||
|  |             outfile = outfile + ".py" | ||||||
|  |             SP.check_call(["pyuic5", "--from-imports", "-o", outfile, file]) | ||||||
							
								
								
									
										5
									
								
								clean.bat
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								clean.bat
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,5 @@ | ||||||
|  | rm -rfv _*.pyd *.egg-info pip-wheel-metadata dist exe build __pycache__ | ||||||
|  | cd rust | ||||||
|  | cargo clean | ||||||
|  | cargo clean --release | ||||||
|  | cd .. | ||||||
							
								
								
									
										2
									
								
								ed_lrr_gui/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								ed_lrr_gui/__init__.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,2 @@ | ||||||
|  | from _ed_lrr import * | ||||||
|  | from . import gui | ||||||
							
								
								
									
										235
									
								
								ed_lrr_gui/__main__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										235
									
								
								ed_lrr_gui/__main__.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,235 @@ | ||||||
|  | import sys | ||||||
|  | from PyQt5.QtCore import QThread, pyqtSignal, Qt | ||||||
|  | from PyQt5.QtWidgets import ( | ||||||
|  |     QMainWindow, | ||||||
|  |     QApplication, | ||||||
|  |     QFileDialog, | ||||||
|  |     QProgressDialog, | ||||||
|  |     QTreeWidgetItem, | ||||||
|  | ) | ||||||
|  | from PyQt5.QtGui import QPalette, QColor | ||||||
|  | import ed_lrr_gui | ||||||
|  | import ed_lrr_gui.config as cfg | ||||||
|  | from ed_lrr_gui.gui.ed_lrr import Ui_ED_LRR | ||||||
|  | import os | ||||||
|  | from datetime import datetime | ||||||
|  | 
 | ||||||
|  | # print(ed_lrr_gui.test({"a": 1, "b": 2})) | ||||||
|  | # exit(1) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Progressdialog(QProgressDialog): | ||||||
|  |     def __init__(self, *args, **kwargs): | ||||||
|  |         super().__init__(*args, **kwargs) | ||||||
|  |         self.setWindowModality(Qt.WindowModal) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class App(QApplication): | ||||||
|  |     def __init__(self): | ||||||
|  |         super().__init__(sys.argv) | ||||||
|  |         self.setStyle("Fusion") | ||||||
|  |         self.set_pallete() | ||||||
|  | 
 | ||||||
|  |     def set_pallete(self): | ||||||
|  |         colors = { | ||||||
|  |             "Window": QColor(53, 53, 53), | ||||||
|  |             "WindowText": Qt.white, | ||||||
|  |             "Base": QColor(15, 15, 15), | ||||||
|  |             "AlternateBase": QColor(53, 53, 53), | ||||||
|  |             "ToolTipBase": Qt.white, | ||||||
|  |             "ToolTipText": Qt.white, | ||||||
|  |             "Text": Qt.white, | ||||||
|  |             "Button": QColor(53, 53, 53), | ||||||
|  |             "ButtonText": Qt.white, | ||||||
|  |             "BrightText": Qt.red, | ||||||
|  |             "Highlight": QColor(255, 128, 0), | ||||||
|  |             "HighlightedText": Qt.black, | ||||||
|  |         } | ||||||
|  |         palette = QPalette() | ||||||
|  |         for entry, color in colors.items(): | ||||||
|  |             palette.setColor(getattr(QPalette, entry), color) | ||||||
|  |             if color == Qt.darkGray: | ||||||
|  |                 palette.setColor( | ||||||
|  |                     QPalette.Disabled, getattr(QPalette, entry), QColor(53, 53, 53) | ||||||
|  |                 ) | ||||||
|  |             else: | ||||||
|  |                 palette.setColor( | ||||||
|  |                     QPalette.Disabled, getattr(QPalette, entry), Qt.darkGray | ||||||
|  |                 ) | ||||||
|  |         self.setPalette(palette) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class ED_LRR(Ui_ED_LRR): | ||||||
|  |     pbar_thread = None | ||||||
|  | 
 | ||||||
|  |     def __init__(self): | ||||||
|  |         super().__init__() | ||||||
|  |         self.config = cfg.load() | ||||||
|  | 
 | ||||||
|  |     def get_open_file(self, filetypes, callback=None): | ||||||
|  |         fileName, _ = QFileDialog.getOpenFileName( | ||||||
|  |             self.main_window, | ||||||
|  |             "Open file", | ||||||
|  |             str(cfg.data_dir), | ||||||
|  |             filetypes, | ||||||
|  |             options=QFileDialog.DontUseNativeDialog, | ||||||
|  |         ) | ||||||
|  |         if callback: | ||||||
|  |             return callback(fileName) | ||||||
|  |         return fileName | ||||||
|  | 
 | ||||||
|  |     def get_save_file(self, filetypes, callback=None): | ||||||
|  |         fileName, _ = QFileDialog.getSaveFileName( | ||||||
|  |             self.main_window, | ||||||
|  |             "Save file", | ||||||
|  |             str(cfg.data_dir), | ||||||
|  |             filetypes, | ||||||
|  |             options=QFileDialog.DontUseNativeDialog, | ||||||
|  |         ) | ||||||
|  |         if callback: | ||||||
|  |             return callback(fileName) | ||||||
|  |         return fileName | ||||||
|  | 
 | ||||||
|  |     def set_sys_lst(self, path): | ||||||
|  |         if path not in self.config.history_out_path: | ||||||
|  |             self.config.history_out_path.append(path) | ||||||
|  |             self.inp_sys_lst.addItem(path) | ||||||
|  |             self.inp_out_pp.addItem(path) | ||||||
|  | 
 | ||||||
|  |     def set_bodies_file(self, path): | ||||||
|  |         if path not in self.config.history_bodies_path: | ||||||
|  |             self.config.history_bodies_path.append(path) | ||||||
|  |             self.inp_bodies_pp.addItem(path) | ||||||
|  | 
 | ||||||
|  |     def set_systems_file(self, path): | ||||||
|  |         if path not in self.config.history_systems_path: | ||||||
|  |             self.config.history_systems_path.append(path) | ||||||
|  |             self.inp_systems_pp.addItem(path) | ||||||
|  | 
 | ||||||
|  |     def update_dropdowns(self): | ||||||
|  |         return | ||||||
|  | 
 | ||||||
|  |     def log(self, *args): | ||||||
|  |         t = datetime.today() | ||||||
|  |         msg_t = "[{}] {}".format(t, str.format(*args)) | ||||||
|  |         self.txt_log.append(msg_t) | ||||||
|  | 
 | ||||||
|  |     def set_comp_mode(self, _): | ||||||
|  |         if self.rd_comp.isChecked(): | ||||||
|  |             comp_mode = "Compute Route" | ||||||
|  |             self.btn_add.setText("Search+Add") | ||||||
|  |             self.lst_sys.setEnabled(True) | ||||||
|  |             self.btn_rm.setEnabled(True) | ||||||
|  |             self.cmb_mode.setEnabled(True) | ||||||
|  |             mode = self.cmb_mode.currentText() | ||||||
|  |             self.set_route_mode(mode) | ||||||
|  |         if self.rd_precomp.isChecked(): | ||||||
|  |             comp_mode = "Precompute Graph" | ||||||
|  |             self.btn_add.setText("Select") | ||||||
|  |             self.lst_sys.setEnabled(False) | ||||||
|  |             self.btn_rm.setEnabled(False) | ||||||
|  |             self.lbl_greedyness.setEnabled(False) | ||||||
|  |             self.sld_greedyness.setEnabled(False) | ||||||
|  |             self.cmb_mode.setEnabled(False) | ||||||
|  | 
 | ||||||
|  |     def set_route_mode(self, mode): | ||||||
|  |         self.lbl_greedyness.setEnabled(mode == "A*-Search") | ||||||
|  |         self.sld_greedyness.setEnabled(mode == "A*-Search") | ||||||
|  | 
 | ||||||
|  |     def set_greedyness(self, value): | ||||||
|  |         val = value / 100 | ||||||
|  |         self.lbl_greedyness.setText("Greedyness Factor ({:.0%})".format(val)) | ||||||
|  | 
 | ||||||
|  |     def sys_to_dict(self, n): | ||||||
|  |         header = [ | ||||||
|  |             self.lst_sys.headerItem().data(c, 0) | ||||||
|  |             for c in range(self.lst_sys.headerItem().columnCount()) | ||||||
|  |         ] | ||||||
|  |         system = [ | ||||||
|  |             self.lst_sys.topLevelItem(n).data(c, 0) | ||||||
|  |             for c in range(self.lst_sys.topLevelItem(n).columnCount()) | ||||||
|  |         ] | ||||||
|  |         return dict(zip(header, system)) | ||||||
|  | 
 | ||||||
|  |     def run(self): | ||||||
|  |         settings = {} | ||||||
|  |         settings["permute"] = [None, False, True][self.chk_permute_keep.checkState()] | ||||||
|  |         settings["range"] = self.sb_range.value() | ||||||
|  |         settings["systems"] = [ | ||||||
|  |             self.sys_to_dict(i) for i in range(self.lst_sys.topLevelItemCount()) | ||||||
|  |         ] | ||||||
|  |         print(settings) | ||||||
|  |         # progress = Progressdialog("TEST\nBLAH", "Cancel", 0, 0, self.main_window) | ||||||
|  |         # progress.setWindowTitle("Computing Route") | ||||||
|  |         # progress.setFixedSize(400, 100) | ||||||
|  |         # progress.setRange(0, 0) | ||||||
|  |         # progress.show() | ||||||
|  | 
 | ||||||
|  |     def add_system(self): | ||||||
|  |         n = self.lst_sys.topLevelItemCount() + 1 | ||||||
|  |         item = QTreeWidgetItem(self.lst_sys, ["A" + str(n), "B" + str(n)]) | ||||||
|  |         item.setFlags(item.flags() & ~Qt.ItemIsDropEnabled) | ||||||
|  | 
 | ||||||
|  |     def remove_system(self): | ||||||
|  |         root = self.lst_sys.invisibleRootItem() | ||||||
|  |         for item in self.lst_sys.selectedItems(): | ||||||
|  |             root.removeChild(item) | ||||||
|  | 
 | ||||||
|  |     def setup_signals(self): | ||||||
|  |         self.set_greedyness(self.sld_greedyness.value()) | ||||||
|  |         self.cmb_mode.currentTextChanged.connect(self.set_route_mode) | ||||||
|  |         self.rd_comp.toggled.connect(self.set_comp_mode) | ||||||
|  |         self.rd_precomp.toggled.connect(self.set_comp_mode) | ||||||
|  |         self.sld_greedyness.valueChanged.connect(self.set_greedyness) | ||||||
|  |         self.btn_go.clicked.connect(self.run) | ||||||
|  |         self.btn_add.clicked.connect(self.add_system) | ||||||
|  |         self.btn_rm.clicked.connect(self.remove_system) | ||||||
|  |         self.btn_out_browse_pp.clicked.connect( | ||||||
|  |             lambda: self.get_save_file("CSV File (*.csv)", self.set_sys_lst) | ||||||
|  |         ) | ||||||
|  |         self.btn_sys_lst_browse.clicked.connect( | ||||||
|  |             lambda: self.get_open_file("CSV File (*.csv)", self.set_sys_lst) | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
|  |         self.btn_bodies_browse_pp.clicked.connect( | ||||||
|  |             lambda: self.get_open_file("JSON File (*.json)", self.set_bodies_file) | ||||||
|  |         ) | ||||||
|  |         self.btn_bodies_dest_browse_dl.clicked.connect( | ||||||
|  |             lambda: self.get_save_file("JSON File (*.json)", self.set_bodies_file) | ||||||
|  |         ) | ||||||
|  |         self.btn_systems_browse_pp.clicked.connect( | ||||||
|  |             lambda: self.get_open_file("JSON File (*.json)", self.set_systems_file) | ||||||
|  |         ) | ||||||
|  |         self.btn_systems_dest_browse_dl.clicked.connect( | ||||||
|  |             lambda: self.get_save_file("JSON File (*.json)", self.set_systems_file) | ||||||
|  |         ) | ||||||
|  |         self.menu_act_quit.triggered.connect(self.app.quit) | ||||||
|  | 
 | ||||||
|  |     def handle_close(self): | ||||||
|  |         cfg.write(self.config) | ||||||
|  |         print("BYEEEEEE!") | ||||||
|  | 
 | ||||||
|  |     def setupUi(self, MainWindow, app): | ||||||
|  |         super().setupUi(MainWindow) | ||||||
|  |         self.update_dropdowns() | ||||||
|  |         self.main_window = MainWindow | ||||||
|  |         self.app = app | ||||||
|  |         self.setup_signals() | ||||||
|  |         self.lst_sys.setHeaderLabels(["Name", "Type"]) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def main(): | ||||||
|  |     import sys | ||||||
|  | 
 | ||||||
|  |     app = App() | ||||||
|  |     MainWindow = QMainWindow() | ||||||
|  |     ui = ED_LRR() | ||||||
|  |     ui.setupUi(MainWindow, app) | ||||||
|  |     MainWindow.show() | ||||||
|  |     ret = app.exec_() | ||||||
|  |     ui.handle_close() | ||||||
|  |     sys.exit(ret) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | if __name__ == "__main__": | ||||||
|  |     main() | ||||||
							
								
								
									
										45
									
								
								ed_lrr_gui/config.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								ed_lrr_gui/config.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,45 @@ | ||||||
|  | import pathlib | ||||||
|  | import appdirs | ||||||
|  | import yaml | ||||||
|  | from collections import namedtuple | ||||||
|  | 
 | ||||||
|  | config_dir = pathlib.Path(appdirs.user_config_dir("ED_LRR")) | ||||||
|  | config_dir.mkdir(parents=True, exist_ok=True) | ||||||
|  | config_file = config_dir / "config.yml" | ||||||
|  | config_file.touch() | ||||||
|  | 
 | ||||||
|  | data_dir = pathlib.Path(appdirs.user_data_dir("ED_LRR")) | ||||||
|  | data_dir.mkdir(parents=True, exist_ok=True) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def make_config(): | ||||||
|  |     return { | ||||||
|  |         "history_bodies_url": [], | ||||||
|  |         "history_systems_url": [], | ||||||
|  |         "history_bodies_path": [], | ||||||
|  |         "history_systems_path": [], | ||||||
|  |         "history_out_path": [], | ||||||
|  |         "range": None, | ||||||
|  |         "primary": False, | ||||||
|  |         "mode": "bfs", | ||||||
|  |         "greedyness": 0.5, | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def write(cfg): | ||||||
|  |     with config_file.open("w", encoding="utf-8") as of: | ||||||
|  |         yaml.dump(cfg._asdict(), of, default_flow_style=False) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def load(): | ||||||
|  |     data = yaml.load(config_file.open(encoding="utf-8"), Loader=yaml.Loader) | ||||||
|  |     if data is None: | ||||||
|  |         data = make_config() | ||||||
|  |         write(data) | ||||||
|  | 
 | ||||||
|  |     return namedtuple("Config", data)(**data) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | # print("CFG:", yaml.load_config()) | ||||||
|  | # print(config_file, data_dir) | ||||||
|  | # exit(1) | ||||||
							
								
								
									
										0
									
								
								ed_lrr_gui/gui/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								ed_lrr_gui/gui/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
								
								
									
										350
									
								
								ed_lrr_gui/gui/ed_lrr.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										350
									
								
								ed_lrr_gui/gui/ed_lrr.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,350 @@ | ||||||
|  | # -*- coding: utf-8 -*- | ||||||
|  | 
 | ||||||
|  | # Form implementation generated from reading ui file 'D:\devel\rust\py_test\ed_lrr_gui\gui\ed_lrr.ui' | ||||||
|  | # | ||||||
|  | # Created by: PyQt5 UI code generator 5.13.0 | ||||||
|  | # | ||||||
|  | # WARNING! All changes made in this file will be lost! | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | from PyQt5 import QtCore, QtGui, QtWidgets | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Ui_ED_LRR(object): | ||||||
|  |     def setupUi(self, ED_LRR): | ||||||
|  |         ED_LRR.setObjectName("ED_LRR") | ||||||
|  |         ED_LRR.setEnabled(True) | ||||||
|  |         ED_LRR.resize(577, 500) | ||||||
|  |         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) | ||||||
|  |         sizePolicy.setHorizontalStretch(0) | ||||||
|  |         sizePolicy.setVerticalStretch(0) | ||||||
|  |         sizePolicy.setHeightForWidth(ED_LRR.sizePolicy().hasHeightForWidth()) | ||||||
|  |         ED_LRR.setSizePolicy(sizePolicy) | ||||||
|  |         ED_LRR.setMinimumSize(QtCore.QSize(577, 500)) | ||||||
|  |         ED_LRR.setMaximumSize(QtCore.QSize(577, 500)) | ||||||
|  |         ED_LRR.setDocumentMode(False) | ||||||
|  |         ED_LRR.setTabShape(QtWidgets.QTabWidget.Rounded) | ||||||
|  |         self.centralwidget = QtWidgets.QWidget(ED_LRR) | ||||||
|  |         self.centralwidget.setObjectName("centralwidget") | ||||||
|  |         self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget) | ||||||
|  |         self.verticalLayout.setObjectName("verticalLayout") | ||||||
|  |         self.tabs = QtWidgets.QTabWidget(self.centralwidget) | ||||||
|  |         self.tabs.setEnabled(True) | ||||||
|  |         self.tabs.setTabShape(QtWidgets.QTabWidget.Rounded) | ||||||
|  |         self.tabs.setTabsClosable(False) | ||||||
|  |         self.tabs.setTabBarAutoHide(False) | ||||||
|  |         self.tabs.setObjectName("tabs") | ||||||
|  |         self.tab_download = QtWidgets.QWidget() | ||||||
|  |         self.tab_download.setObjectName("tab_download") | ||||||
|  |         self.formLayout = QtWidgets.QFormLayout(self.tab_download) | ||||||
|  |         self.formLayout.setObjectName("formLayout") | ||||||
|  |         self.lbl_bodies_dl = QtWidgets.QLabel(self.tab_download) | ||||||
|  |         self.lbl_bodies_dl.setObjectName("lbl_bodies_dl") | ||||||
|  |         self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.lbl_bodies_dl) | ||||||
|  |         self.lbl_systems_dl = QtWidgets.QLabel(self.tab_download) | ||||||
|  |         self.lbl_systems_dl.setObjectName("lbl_systems_dl") | ||||||
|  |         self.formLayout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.lbl_systems_dl) | ||||||
|  |         self.inp_bodies_dl = QtWidgets.QComboBox(self.tab_download) | ||||||
|  |         self.inp_bodies_dl.setEditable(True) | ||||||
|  |         self.inp_bodies_dl.setObjectName("inp_bodies_dl") | ||||||
|  |         self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.inp_bodies_dl) | ||||||
|  |         self.inp_systems_dl = QtWidgets.QComboBox(self.tab_download) | ||||||
|  |         self.inp_systems_dl.setEditable(True) | ||||||
|  |         self.inp_systems_dl.setObjectName("inp_systems_dl") | ||||||
|  |         self.formLayout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.inp_systems_dl) | ||||||
|  |         self.gridLayout = QtWidgets.QGridLayout() | ||||||
|  |         self.gridLayout.setObjectName("gridLayout") | ||||||
|  |         self.inp_bodies_dest_dl = QtWidgets.QComboBox(self.tab_download) | ||||||
|  |         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) | ||||||
|  |         sizePolicy.setHorizontalStretch(0) | ||||||
|  |         sizePolicy.setVerticalStretch(0) | ||||||
|  |         sizePolicy.setHeightForWidth(self.inp_bodies_dest_dl.sizePolicy().hasHeightForWidth()) | ||||||
|  |         self.inp_bodies_dest_dl.setSizePolicy(sizePolicy) | ||||||
|  |         self.inp_bodies_dest_dl.setEditable(True) | ||||||
|  |         self.inp_bodies_dest_dl.setObjectName("inp_bodies_dest_dl") | ||||||
|  |         self.gridLayout.addWidget(self.inp_bodies_dest_dl, 0, 0, 1, 1) | ||||||
|  |         self.btn_bodies_dest_browse_dl = QtWidgets.QPushButton(self.tab_download) | ||||||
|  |         self.btn_bodies_dest_browse_dl.setObjectName("btn_bodies_dest_browse_dl") | ||||||
|  |         self.gridLayout.addWidget(self.btn_bodies_dest_browse_dl, 0, 1, 1, 1) | ||||||
|  |         self.formLayout.setLayout(2, QtWidgets.QFormLayout.FieldRole, self.gridLayout) | ||||||
|  |         self.gridLayout_2 = QtWidgets.QGridLayout() | ||||||
|  |         self.gridLayout_2.setObjectName("gridLayout_2") | ||||||
|  |         self.btn_systems_dest_browse_dl = QtWidgets.QPushButton(self.tab_download) | ||||||
|  |         self.btn_systems_dest_browse_dl.setObjectName("btn_systems_dest_browse_dl") | ||||||
|  |         self.gridLayout_2.addWidget(self.btn_systems_dest_browse_dl, 0, 1, 1, 1) | ||||||
|  |         self.inp_systems_dest_dl = QtWidgets.QComboBox(self.tab_download) | ||||||
|  |         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) | ||||||
|  |         sizePolicy.setHorizontalStretch(0) | ||||||
|  |         sizePolicy.setVerticalStretch(0) | ||||||
|  |         sizePolicy.setHeightForWidth(self.inp_systems_dest_dl.sizePolicy().hasHeightForWidth()) | ||||||
|  |         self.inp_systems_dest_dl.setSizePolicy(sizePolicy) | ||||||
|  |         self.inp_systems_dest_dl.setEditable(True) | ||||||
|  |         self.inp_systems_dest_dl.setObjectName("inp_systems_dest_dl") | ||||||
|  |         self.gridLayout_2.addWidget(self.inp_systems_dest_dl, 0, 0, 1, 1) | ||||||
|  |         self.formLayout.setLayout(4, QtWidgets.QFormLayout.FieldRole, self.gridLayout_2) | ||||||
|  |         self.btn_download = QtWidgets.QPushButton(self.tab_download) | ||||||
|  |         self.btn_download.setObjectName("btn_download") | ||||||
|  |         self.formLayout.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.btn_download) | ||||||
|  |         self.label = QtWidgets.QLabel(self.tab_download) | ||||||
|  |         self.label.setObjectName("label") | ||||||
|  |         self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label) | ||||||
|  |         self.label_2 = QtWidgets.QLabel(self.tab_download) | ||||||
|  |         self.label_2.setObjectName("label_2") | ||||||
|  |         self.formLayout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.label_2) | ||||||
|  |         self.tabs.addTab(self.tab_download, "") | ||||||
|  |         self.tab_preprocess = QtWidgets.QWidget() | ||||||
|  |         self.tab_preprocess.setObjectName("tab_preprocess") | ||||||
|  |         self.formLayout_3 = QtWidgets.QFormLayout(self.tab_preprocess) | ||||||
|  |         self.formLayout_3.setObjectName("formLayout_3") | ||||||
|  |         self.lbl_bodies_pp = QtWidgets.QLabel(self.tab_preprocess) | ||||||
|  |         self.lbl_bodies_pp.setObjectName("lbl_bodies_pp") | ||||||
|  |         self.formLayout_3.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.lbl_bodies_pp) | ||||||
|  |         self.gr_bodies_pp = QtWidgets.QGridLayout() | ||||||
|  |         self.gr_bodies_pp.setObjectName("gr_bodies_pp") | ||||||
|  |         self.btn_bodies_browse_pp = QtWidgets.QPushButton(self.tab_preprocess) | ||||||
|  |         self.btn_bodies_browse_pp.setObjectName("btn_bodies_browse_pp") | ||||||
|  |         self.gr_bodies_pp.addWidget(self.btn_bodies_browse_pp, 0, 1, 1, 1) | ||||||
|  |         self.inp_bodies_pp = QtWidgets.QComboBox(self.tab_preprocess) | ||||||
|  |         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) | ||||||
|  |         sizePolicy.setHorizontalStretch(0) | ||||||
|  |         sizePolicy.setVerticalStretch(0) | ||||||
|  |         sizePolicy.setHeightForWidth(self.inp_bodies_pp.sizePolicy().hasHeightForWidth()) | ||||||
|  |         self.inp_bodies_pp.setSizePolicy(sizePolicy) | ||||||
|  |         self.inp_bodies_pp.setEditable(True) | ||||||
|  |         self.inp_bodies_pp.setObjectName("inp_bodies_pp") | ||||||
|  |         self.gr_bodies_pp.addWidget(self.inp_bodies_pp, 0, 0, 1, 1) | ||||||
|  |         self.formLayout_3.setLayout(0, QtWidgets.QFormLayout.FieldRole, self.gr_bodies_pp) | ||||||
|  |         self.lbl_systems_pp = QtWidgets.QLabel(self.tab_preprocess) | ||||||
|  |         self.lbl_systems_pp.setObjectName("lbl_systems_pp") | ||||||
|  |         self.formLayout_3.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.lbl_systems_pp) | ||||||
|  |         self.gr_systems_pp = QtWidgets.QGridLayout() | ||||||
|  |         self.gr_systems_pp.setObjectName("gr_systems_pp") | ||||||
|  |         self.btn_systems_browse_pp = QtWidgets.QPushButton(self.tab_preprocess) | ||||||
|  |         self.btn_systems_browse_pp.setObjectName("btn_systems_browse_pp") | ||||||
|  |         self.gr_systems_pp.addWidget(self.btn_systems_browse_pp, 0, 1, 1, 1) | ||||||
|  |         self.inp_systems_pp = QtWidgets.QComboBox(self.tab_preprocess) | ||||||
|  |         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) | ||||||
|  |         sizePolicy.setHorizontalStretch(0) | ||||||
|  |         sizePolicy.setVerticalStretch(0) | ||||||
|  |         sizePolicy.setHeightForWidth(self.inp_systems_pp.sizePolicy().hasHeightForWidth()) | ||||||
|  |         self.inp_systems_pp.setSizePolicy(sizePolicy) | ||||||
|  |         self.inp_systems_pp.setEditable(True) | ||||||
|  |         self.inp_systems_pp.setObjectName("inp_systems_pp") | ||||||
|  |         self.gr_systems_pp.addWidget(self.inp_systems_pp, 0, 0, 1, 1) | ||||||
|  |         self.formLayout_3.setLayout(1, QtWidgets.QFormLayout.FieldRole, self.gr_systems_pp) | ||||||
|  |         self.lbl_out_pp = QtWidgets.QLabel(self.tab_preprocess) | ||||||
|  |         self.lbl_out_pp.setObjectName("lbl_out_pp") | ||||||
|  |         self.formLayout_3.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.lbl_out_pp) | ||||||
|  |         self.gr_out_grid_pp = QtWidgets.QGridLayout() | ||||||
|  |         self.gr_out_grid_pp.setObjectName("gr_out_grid_pp") | ||||||
|  |         self.btn_out_browse_pp = QtWidgets.QPushButton(self.tab_preprocess) | ||||||
|  |         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) | ||||||
|  |         sizePolicy.setHorizontalStretch(0) | ||||||
|  |         sizePolicy.setVerticalStretch(0) | ||||||
|  |         sizePolicy.setHeightForWidth(self.btn_out_browse_pp.sizePolicy().hasHeightForWidth()) | ||||||
|  |         self.btn_out_browse_pp.setSizePolicy(sizePolicy) | ||||||
|  |         self.btn_out_browse_pp.setObjectName("btn_out_browse_pp") | ||||||
|  |         self.gr_out_grid_pp.addWidget(self.btn_out_browse_pp, 0, 1, 1, 1) | ||||||
|  |         self.inp_out_pp = QtWidgets.QComboBox(self.tab_preprocess) | ||||||
|  |         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) | ||||||
|  |         sizePolicy.setHorizontalStretch(0) | ||||||
|  |         sizePolicy.setVerticalStretch(0) | ||||||
|  |         sizePolicy.setHeightForWidth(self.inp_out_pp.sizePolicy().hasHeightForWidth()) | ||||||
|  |         self.inp_out_pp.setSizePolicy(sizePolicy) | ||||||
|  |         self.inp_out_pp.setEditable(True) | ||||||
|  |         self.inp_out_pp.setObjectName("inp_out_pp") | ||||||
|  |         self.gr_out_grid_pp.addWidget(self.inp_out_pp, 0, 0, 1, 1) | ||||||
|  |         self.formLayout_3.setLayout(2, QtWidgets.QFormLayout.FieldRole, self.gr_out_grid_pp) | ||||||
|  |         self.btn_preprocess = QtWidgets.QPushButton(self.tab_preprocess) | ||||||
|  |         self.btn_preprocess.setObjectName("btn_preprocess") | ||||||
|  |         self.formLayout_3.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.btn_preprocess) | ||||||
|  |         self.tabs.addTab(self.tab_preprocess, "") | ||||||
|  |         self.tab_route = QtWidgets.QWidget() | ||||||
|  |         self.tab_route.setObjectName("tab_route") | ||||||
|  |         self.formLayout_2 = QtWidgets.QFormLayout(self.tab_route) | ||||||
|  |         self.formLayout_2.setObjectName("formLayout_2") | ||||||
|  |         self.lbl_sys_lst = QtWidgets.QLabel(self.tab_route) | ||||||
|  |         self.lbl_sys_lst.setObjectName("lbl_sys_lst") | ||||||
|  |         self.formLayout_2.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.lbl_sys_lst) | ||||||
|  |         self.gr_sys = QtWidgets.QGridLayout() | ||||||
|  |         self.gr_sys.setObjectName("gr_sys") | ||||||
|  |         self.btn_sys_lst_browse = QtWidgets.QPushButton(self.tab_route) | ||||||
|  |         self.btn_sys_lst_browse.setObjectName("btn_sys_lst_browse") | ||||||
|  |         self.gr_sys.addWidget(self.btn_sys_lst_browse, 0, 1, 1, 1) | ||||||
|  |         self.inp_sys_lst = QtWidgets.QComboBox(self.tab_route) | ||||||
|  |         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) | ||||||
|  |         sizePolicy.setHorizontalStretch(0) | ||||||
|  |         sizePolicy.setVerticalStretch(0) | ||||||
|  |         sizePolicy.setHeightForWidth(self.inp_sys_lst.sizePolicy().hasHeightForWidth()) | ||||||
|  |         self.inp_sys_lst.setSizePolicy(sizePolicy) | ||||||
|  |         self.inp_sys_lst.setEditable(True) | ||||||
|  |         self.inp_sys_lst.setObjectName("inp_sys_lst") | ||||||
|  |         self.gr_sys.addWidget(self.inp_sys_lst, 0, 0, 1, 1) | ||||||
|  |         self.formLayout_2.setLayout(0, QtWidgets.QFormLayout.FieldRole, self.gr_sys) | ||||||
|  |         self.btn_add = QtWidgets.QPushButton(self.tab_route) | ||||||
|  |         self.btn_add.setObjectName("btn_add") | ||||||
|  |         self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.btn_add) | ||||||
|  |         self.inp_sys = QtWidgets.QLineEdit(self.tab_route) | ||||||
|  |         self.inp_sys.setObjectName("inp_sys") | ||||||
|  |         self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.inp_sys) | ||||||
|  |         self.btn_rm = QtWidgets.QPushButton(self.tab_route) | ||||||
|  |         self.btn_rm.setObjectName("btn_rm") | ||||||
|  |         self.formLayout_2.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.btn_rm) | ||||||
|  |         self.gr_mode = QtWidgets.QGridLayout() | ||||||
|  |         self.gr_mode.setObjectName("gr_mode") | ||||||
|  |         self.rd_comp = QtWidgets.QRadioButton(self.tab_route) | ||||||
|  |         self.rd_comp.setChecked(True) | ||||||
|  |         self.rd_comp.setObjectName("rd_comp") | ||||||
|  |         self.gr_mode.addWidget(self.rd_comp, 0, 1, 1, 1) | ||||||
|  |         self.rd_precomp = QtWidgets.QRadioButton(self.tab_route) | ||||||
|  |         self.rd_precomp.setObjectName("rd_precomp") | ||||||
|  |         self.gr_mode.addWidget(self.rd_precomp, 0, 2, 1, 1) | ||||||
|  |         self.formLayout_2.setLayout(3, QtWidgets.QFormLayout.FieldRole, self.gr_mode) | ||||||
|  |         self.btn_permute = QtWidgets.QPushButton(self.tab_route) | ||||||
|  |         self.btn_permute.setObjectName("btn_permute") | ||||||
|  |         self.formLayout_2.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.btn_permute) | ||||||
|  |         self.chk_permute_keep = QtWidgets.QCheckBox(self.tab_route) | ||||||
|  |         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) | ||||||
|  |         sizePolicy.setHorizontalStretch(0) | ||||||
|  |         sizePolicy.setVerticalStretch(0) | ||||||
|  |         sizePolicy.setHeightForWidth(self.chk_permute_keep.sizePolicy().hasHeightForWidth()) | ||||||
|  |         self.chk_permute_keep.setSizePolicy(sizePolicy) | ||||||
|  |         self.chk_permute_keep.setTristate(True) | ||||||
|  |         self.chk_permute_keep.setObjectName("chk_permute_keep") | ||||||
|  |         self.formLayout_2.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.chk_permute_keep) | ||||||
|  |         self.lst_sys = QtWidgets.QTreeWidget(self.tab_route) | ||||||
|  |         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) | ||||||
|  |         sizePolicy.setHorizontalStretch(0) | ||||||
|  |         sizePolicy.setVerticalStretch(0) | ||||||
|  |         sizePolicy.setHeightForWidth(self.lst_sys.sizePolicy().hasHeightForWidth()) | ||||||
|  |         self.lst_sys.setSizePolicy(sizePolicy) | ||||||
|  |         self.lst_sys.setMinimumSize(QtCore.QSize(0, 0)) | ||||||
|  |         self.lst_sys.setDragEnabled(True) | ||||||
|  |         self.lst_sys.setDragDropOverwriteMode(False) | ||||||
|  |         self.lst_sys.setDragDropMode(QtWidgets.QAbstractItemView.InternalMove) | ||||||
|  |         self.lst_sys.setDefaultDropAction(QtCore.Qt.MoveAction) | ||||||
|  |         self.lst_sys.setAlternatingRowColors(True) | ||||||
|  |         self.lst_sys.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) | ||||||
|  |         self.lst_sys.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) | ||||||
|  |         self.lst_sys.setObjectName("lst_sys") | ||||||
|  |         self.lst_sys.headerItem().setText(0, "1") | ||||||
|  |         self.formLayout_2.setWidget(5, QtWidgets.QFormLayout.SpanningRole, self.lst_sys) | ||||||
|  |         self.sb_range = QtWidgets.QDoubleSpinBox(self.tab_route) | ||||||
|  |         self.sb_range.setObjectName("sb_range") | ||||||
|  |         self.formLayout_2.setWidget(6, QtWidgets.QFormLayout.FieldRole, self.sb_range) | ||||||
|  |         self.lbl_range = QtWidgets.QLabel(self.tab_route) | ||||||
|  |         self.lbl_range.setObjectName("lbl_range") | ||||||
|  |         self.formLayout_2.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.lbl_range) | ||||||
|  |         self.gr_opts = QtWidgets.QGridLayout() | ||||||
|  |         self.gr_opts.setObjectName("gr_opts") | ||||||
|  |         self.cmb_mode = QtWidgets.QComboBox(self.tab_route) | ||||||
|  |         self.cmb_mode.setObjectName("cmb_mode") | ||||||
|  |         self.cmb_mode.addItem("") | ||||||
|  |         self.cmb_mode.addItem("") | ||||||
|  |         self.cmb_mode.addItem("") | ||||||
|  |         self.gr_opts.addWidget(self.cmb_mode, 0, 2, 1, 1) | ||||||
|  |         self.lbl_greedyness = QtWidgets.QLabel(self.tab_route) | ||||||
|  |         self.lbl_greedyness.setEnabled(True) | ||||||
|  |         self.lbl_greedyness.setObjectName("lbl_greedyness") | ||||||
|  |         self.gr_opts.addWidget(self.lbl_greedyness, 1, 1, 1, 1) | ||||||
|  |         self.chk_primary = QtWidgets.QCheckBox(self.tab_route) | ||||||
|  |         self.chk_primary.setObjectName("chk_primary") | ||||||
|  |         self.gr_opts.addWidget(self.chk_primary, 0, 3, 1, 1) | ||||||
|  |         self.sld_greedyness = QtWidgets.QSlider(self.tab_route) | ||||||
|  |         self.sld_greedyness.setMaximum(100) | ||||||
|  |         self.sld_greedyness.setPageStep(10) | ||||||
|  |         self.sld_greedyness.setProperty("value", 50) | ||||||
|  |         self.sld_greedyness.setOrientation(QtCore.Qt.Horizontal) | ||||||
|  |         self.sld_greedyness.setTickPosition(QtWidgets.QSlider.TicksBelow) | ||||||
|  |         self.sld_greedyness.setTickInterval(10) | ||||||
|  |         self.sld_greedyness.setObjectName("sld_greedyness") | ||||||
|  |         self.gr_opts.addWidget(self.sld_greedyness, 1, 2, 1, 2) | ||||||
|  |         self.lbl_mode = QtWidgets.QLabel(self.tab_route) | ||||||
|  |         self.lbl_mode.setObjectName("lbl_mode") | ||||||
|  |         self.gr_opts.addWidget(self.lbl_mode, 0, 1, 1, 1) | ||||||
|  |         self.formLayout_2.setLayout(7, QtWidgets.QFormLayout.SpanningRole, self.gr_opts) | ||||||
|  |         self.btn_go = QtWidgets.QPushButton(self.tab_route) | ||||||
|  |         self.btn_go.setFlat(False) | ||||||
|  |         self.btn_go.setObjectName("btn_go") | ||||||
|  |         self.formLayout_2.setWidget(8, QtWidgets.QFormLayout.LabelRole, self.btn_go) | ||||||
|  |         self.tabs.addTab(self.tab_route, "") | ||||||
|  |         self.tab_log = QtWidgets.QWidget() | ||||||
|  |         self.tab_log.setObjectName("tab_log") | ||||||
|  |         self.gridLayout_3 = QtWidgets.QGridLayout(self.tab_log) | ||||||
|  |         self.gridLayout_3.setObjectName("gridLayout_3") | ||||||
|  |         self.txt_log = QtWidgets.QTextEdit(self.tab_log) | ||||||
|  |         self.txt_log.setEnabled(True) | ||||||
|  |         self.txt_log.setFrameShadow(QtWidgets.QFrame.Sunken) | ||||||
|  |         self.txt_log.setLineWidth(1) | ||||||
|  |         self.txt_log.setReadOnly(True) | ||||||
|  |         self.txt_log.setAcceptRichText(False) | ||||||
|  |         self.txt_log.setObjectName("txt_log") | ||||||
|  |         self.gridLayout_3.addWidget(self.txt_log, 0, 0, 1, 1) | ||||||
|  |         self.tabs.addTab(self.tab_log, "") | ||||||
|  |         self.verticalLayout.addWidget(self.tabs) | ||||||
|  |         ED_LRR.setCentralWidget(self.centralwidget) | ||||||
|  |         self.menu = QtWidgets.QMenuBar(ED_LRR) | ||||||
|  |         self.menu.setGeometry(QtCore.QRect(0, 0, 577, 21)) | ||||||
|  |         self.menu.setObjectName("menu") | ||||||
|  |         self.menu_file = QtWidgets.QMenu(self.menu) | ||||||
|  |         self.menu_file.setObjectName("menu_file") | ||||||
|  |         ED_LRR.setMenuBar(self.menu) | ||||||
|  |         self.bar_status = QtWidgets.QStatusBar(ED_LRR) | ||||||
|  |         self.bar_status.setObjectName("bar_status") | ||||||
|  |         ED_LRR.setStatusBar(self.bar_status) | ||||||
|  |         self.menu_act_quit = QtWidgets.QAction(ED_LRR) | ||||||
|  |         self.menu_act_quit.setObjectName("menu_act_quit") | ||||||
|  |         self.menu_file.addAction(self.menu_act_quit) | ||||||
|  |         self.menu.addAction(self.menu_file.menuAction()) | ||||||
|  | 
 | ||||||
|  |         self.retranslateUi(ED_LRR) | ||||||
|  |         self.tabs.setCurrentIndex(2) | ||||||
|  |         QtCore.QMetaObject.connectSlotsByName(ED_LRR) | ||||||
|  |         ED_LRR.setTabOrder(self.rd_comp, self.cmb_mode) | ||||||
|  |         ED_LRR.setTabOrder(self.cmb_mode, self.chk_primary) | ||||||
|  |         ED_LRR.setTabOrder(self.chk_primary, self.sld_greedyness) | ||||||
|  |         ED_LRR.setTabOrder(self.sld_greedyness, self.rd_precomp) | ||||||
|  | 
 | ||||||
|  |     def retranslateUi(self, ED_LRR): | ||||||
|  |         _translate = QtCore.QCoreApplication.translate | ||||||
|  |         ED_LRR.setWindowTitle(_translate("ED_LRR", "Elite: Dangerous Long Range Route Plotter")) | ||||||
|  |         self.lbl_bodies_dl.setText(_translate("ED_LRR", "bodies.json")) | ||||||
|  |         self.lbl_systems_dl.setText(_translate("ED_LRR", "systemsWithCoordinates.json")) | ||||||
|  |         self.inp_bodies_dl.setCurrentText(_translate("ED_LRR", "https://www.edsm.net/dump/bodies.json")) | ||||||
|  |         self.inp_systems_dl.setCurrentText(_translate("ED_LRR", "https://www.edsm.net/dump/systemsWithCoordinates.json")) | ||||||
|  |         self.btn_bodies_dest_browse_dl.setText(_translate("ED_LRR", "...")) | ||||||
|  |         self.btn_systems_dest_browse_dl.setText(_translate("ED_LRR", "...")) | ||||||
|  |         self.btn_download.setText(_translate("ED_LRR", "Download")) | ||||||
|  |         self.label.setText(_translate("ED_LRR", "Download path")) | ||||||
|  |         self.label_2.setText(_translate("ED_LRR", "Download path")) | ||||||
|  |         self.tabs.setTabText(self.tabs.indexOf(self.tab_download), _translate("ED_LRR", "Download")) | ||||||
|  |         self.lbl_bodies_pp.setText(_translate("ED_LRR", "bodies.json")) | ||||||
|  |         self.btn_bodies_browse_pp.setText(_translate("ED_LRR", "...")) | ||||||
|  |         self.lbl_systems_pp.setText(_translate("ED_LRR", "systemsWithCoordinates.json")) | ||||||
|  |         self.btn_systems_browse_pp.setText(_translate("ED_LRR", "...")) | ||||||
|  |         self.lbl_out_pp.setText(_translate("ED_LRR", "Output")) | ||||||
|  |         self.btn_out_browse_pp.setText(_translate("ED_LRR", "...")) | ||||||
|  |         self.btn_preprocess.setText(_translate("ED_LRR", "Preprocess")) | ||||||
|  |         self.tabs.setTabText(self.tabs.indexOf(self.tab_preprocess), _translate("ED_LRR", "Preprocess")) | ||||||
|  |         self.lbl_sys_lst.setText(_translate("ED_LRR", "System List")) | ||||||
|  |         self.btn_sys_lst_browse.setText(_translate("ED_LRR", "...")) | ||||||
|  |         self.btn_add.setText(_translate("ED_LRR", "Search+Add")) | ||||||
|  |         self.btn_rm.setText(_translate("ED_LRR", "Remove")) | ||||||
|  |         self.rd_comp.setText(_translate("ED_LRR", "Compute Route")) | ||||||
|  |         self.rd_precomp.setText(_translate("ED_LRR", "Precompute Graph")) | ||||||
|  |         self.btn_permute.setText(_translate("ED_LRR", "Permute")) | ||||||
|  |         self.chk_permute_keep.setText(_translate("ED_LRR", "Keep endpoints (No, first only, yes)")) | ||||||
|  |         self.lbl_range.setText(_translate("ED_LRR", "Jump Range (Ly)")) | ||||||
|  |         self.cmb_mode.setCurrentText(_translate("ED_LRR", "Breadth-First Search")) | ||||||
|  |         self.cmb_mode.setItemText(0, _translate("ED_LRR", "Breadth-First Search")) | ||||||
|  |         self.cmb_mode.setItemText(1, _translate("ED_LRR", "Greedy-Search")) | ||||||
|  |         self.cmb_mode.setItemText(2, _translate("ED_LRR", "A*-Search")) | ||||||
|  |         self.lbl_greedyness.setText(_translate("ED_LRR", "Greedyness Factor")) | ||||||
|  |         self.chk_primary.setText(_translate("ED_LRR", "Primary Stars Only")) | ||||||
|  |         self.lbl_mode.setText(_translate("ED_LRR", "Mode")) | ||||||
|  |         self.btn_go.setText(_translate("ED_LRR", "GO!")) | ||||||
|  |         self.tabs.setTabText(self.tabs.indexOf(self.tab_route), _translate("ED_LRR", "Route")) | ||||||
|  |         self.tabs.setTabText(self.tabs.indexOf(self.tab_log), _translate("ED_LRR", "Log")) | ||||||
|  |         self.menu_file.setTitle(_translate("ED_LRR", "File")) | ||||||
|  |         self.menu_act_quit.setText(_translate("ED_LRR", "Quit")) | ||||||
|  |         self.menu_act_quit.setShortcut(_translate("ED_LRR", "Ctrl+Q")) | ||||||
							
								
								
									
										584
									
								
								ed_lrr_gui/gui/ed_lrr.ui
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										584
									
								
								ed_lrr_gui/gui/ed_lrr.ui
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,584 @@ | ||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <ui version="4.0"> | ||||||
|  |  <class>ED_LRR</class> | ||||||
|  |  <widget class="QMainWindow" name="ED_LRR"> | ||||||
|  |   <property name="enabled"> | ||||||
|  |    <bool>true</bool> | ||||||
|  |   </property> | ||||||
|  |   <property name="geometry"> | ||||||
|  |    <rect> | ||||||
|  |     <x>0</x> | ||||||
|  |     <y>0</y> | ||||||
|  |     <width>577</width> | ||||||
|  |     <height>500</height> | ||||||
|  |    </rect> | ||||||
|  |   </property> | ||||||
|  |   <property name="sizePolicy"> | ||||||
|  |    <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> | ||||||
|  |     <horstretch>0</horstretch> | ||||||
|  |     <verstretch>0</verstretch> | ||||||
|  |    </sizepolicy> | ||||||
|  |   </property> | ||||||
|  |   <property name="minimumSize"> | ||||||
|  |    <size> | ||||||
|  |     <width>577</width> | ||||||
|  |     <height>500</height> | ||||||
|  |    </size> | ||||||
|  |   </property> | ||||||
|  |   <property name="maximumSize"> | ||||||
|  |    <size> | ||||||
|  |     <width>577</width> | ||||||
|  |     <height>500</height> | ||||||
|  |    </size> | ||||||
|  |   </property> | ||||||
|  |   <property name="windowTitle"> | ||||||
|  |    <string>Elite: Dangerous Long Range Route Plotter</string> | ||||||
|  |   </property> | ||||||
|  |   <property name="documentMode"> | ||||||
|  |    <bool>false</bool> | ||||||
|  |   </property> | ||||||
|  |   <property name="tabShape"> | ||||||
|  |    <enum>QTabWidget::Rounded</enum> | ||||||
|  |   </property> | ||||||
|  |   <widget class="QWidget" name="centralwidget"> | ||||||
|  |    <layout class="QVBoxLayout" name="verticalLayout"> | ||||||
|  |     <item> | ||||||
|  |      <widget class="QTabWidget" name="tabs"> | ||||||
|  |       <property name="enabled"> | ||||||
|  |        <bool>true</bool> | ||||||
|  |       </property> | ||||||
|  |       <property name="tabShape"> | ||||||
|  |        <enum>QTabWidget::Rounded</enum> | ||||||
|  |       </property> | ||||||
|  |       <property name="currentIndex"> | ||||||
|  |        <number>2</number> | ||||||
|  |       </property> | ||||||
|  |       <property name="tabsClosable"> | ||||||
|  |        <bool>false</bool> | ||||||
|  |       </property> | ||||||
|  |       <property name="tabBarAutoHide"> | ||||||
|  |        <bool>false</bool> | ||||||
|  |       </property> | ||||||
|  |       <widget class="QWidget" name="tab_download"> | ||||||
|  |        <attribute name="title"> | ||||||
|  |         <string>Download</string> | ||||||
|  |        </attribute> | ||||||
|  |        <layout class="QFormLayout" name="formLayout"> | ||||||
|  |         <item row="1" column="0"> | ||||||
|  |          <widget class="QLabel" name="lbl_bodies_dl"> | ||||||
|  |           <property name="text"> | ||||||
|  |            <string>bodies.json</string> | ||||||
|  |           </property> | ||||||
|  |          </widget> | ||||||
|  |         </item> | ||||||
|  |         <item row="3" column="0"> | ||||||
|  |          <widget class="QLabel" name="lbl_systems_dl"> | ||||||
|  |           <property name="text"> | ||||||
|  |            <string>systemsWithCoordinates.json</string> | ||||||
|  |           </property> | ||||||
|  |          </widget> | ||||||
|  |         </item> | ||||||
|  |         <item row="1" column="1"> | ||||||
|  |          <widget class="QComboBox" name="inp_bodies_dl"> | ||||||
|  |           <property name="editable"> | ||||||
|  |            <bool>true</bool> | ||||||
|  |           </property> | ||||||
|  |           <property name="currentText"> | ||||||
|  |            <string>https://www.edsm.net/dump/bodies.json</string> | ||||||
|  |           </property> | ||||||
|  |          </widget> | ||||||
|  |         </item> | ||||||
|  |         <item row="3" column="1"> | ||||||
|  |          <widget class="QComboBox" name="inp_systems_dl"> | ||||||
|  |           <property name="editable"> | ||||||
|  |            <bool>true</bool> | ||||||
|  |           </property> | ||||||
|  |           <property name="currentText"> | ||||||
|  |            <string>https://www.edsm.net/dump/systemsWithCoordinates.json</string> | ||||||
|  |           </property> | ||||||
|  |          </widget> | ||||||
|  |         </item> | ||||||
|  |         <item row="2" column="1"> | ||||||
|  |          <layout class="QGridLayout" name="gridLayout"> | ||||||
|  |           <item row="0" column="0"> | ||||||
|  |            <widget class="QComboBox" name="inp_bodies_dest_dl"> | ||||||
|  |             <property name="sizePolicy"> | ||||||
|  |              <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> | ||||||
|  |               <horstretch>0</horstretch> | ||||||
|  |               <verstretch>0</verstretch> | ||||||
|  |              </sizepolicy> | ||||||
|  |             </property> | ||||||
|  |             <property name="editable"> | ||||||
|  |              <bool>true</bool> | ||||||
|  |             </property> | ||||||
|  |            </widget> | ||||||
|  |           </item> | ||||||
|  |           <item row="0" column="1"> | ||||||
|  |            <widget class="QPushButton" name="btn_bodies_dest_browse_dl"> | ||||||
|  |             <property name="text"> | ||||||
|  |              <string>...</string> | ||||||
|  |             </property> | ||||||
|  |            </widget> | ||||||
|  |           </item> | ||||||
|  |          </layout> | ||||||
|  |         </item> | ||||||
|  |         <item row="4" column="1"> | ||||||
|  |          <layout class="QGridLayout" name="gridLayout_2"> | ||||||
|  |           <item row="0" column="1"> | ||||||
|  |            <widget class="QPushButton" name="btn_systems_dest_browse_dl"> | ||||||
|  |             <property name="text"> | ||||||
|  |              <string>...</string> | ||||||
|  |             </property> | ||||||
|  |            </widget> | ||||||
|  |           </item> | ||||||
|  |           <item row="0" column="0"> | ||||||
|  |            <widget class="QComboBox" name="inp_systems_dest_dl"> | ||||||
|  |             <property name="sizePolicy"> | ||||||
|  |              <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> | ||||||
|  |               <horstretch>0</horstretch> | ||||||
|  |               <verstretch>0</verstretch> | ||||||
|  |              </sizepolicy> | ||||||
|  |             </property> | ||||||
|  |             <property name="editable"> | ||||||
|  |              <bool>true</bool> | ||||||
|  |             </property> | ||||||
|  |            </widget> | ||||||
|  |           </item> | ||||||
|  |          </layout> | ||||||
|  |         </item> | ||||||
|  |         <item row="5" column="0"> | ||||||
|  |          <widget class="QPushButton" name="btn_download"> | ||||||
|  |           <property name="text"> | ||||||
|  |            <string>Download</string> | ||||||
|  |           </property> | ||||||
|  |          </widget> | ||||||
|  |         </item> | ||||||
|  |         <item row="2" column="0"> | ||||||
|  |          <widget class="QLabel" name="label"> | ||||||
|  |           <property name="text"> | ||||||
|  |            <string>Download path</string> | ||||||
|  |           </property> | ||||||
|  |          </widget> | ||||||
|  |         </item> | ||||||
|  |         <item row="4" column="0"> | ||||||
|  |          <widget class="QLabel" name="label_2"> | ||||||
|  |           <property name="text"> | ||||||
|  |            <string>Download path</string> | ||||||
|  |           </property> | ||||||
|  |          </widget> | ||||||
|  |         </item> | ||||||
|  |        </layout> | ||||||
|  |       </widget> | ||||||
|  |       <widget class="QWidget" name="tab_preprocess"> | ||||||
|  |        <attribute name="title"> | ||||||
|  |         <string>Preprocess</string> | ||||||
|  |        </attribute> | ||||||
|  |        <layout class="QFormLayout" name="formLayout_3"> | ||||||
|  |         <item row="0" column="0"> | ||||||
|  |          <widget class="QLabel" name="lbl_bodies_pp"> | ||||||
|  |           <property name="text"> | ||||||
|  |            <string>bodies.json</string> | ||||||
|  |           </property> | ||||||
|  |          </widget> | ||||||
|  |         </item> | ||||||
|  |         <item row="0" column="1"> | ||||||
|  |          <layout class="QGridLayout" name="gr_bodies_pp"> | ||||||
|  |           <item row="0" column="1"> | ||||||
|  |            <widget class="QPushButton" name="btn_bodies_browse_pp"> | ||||||
|  |             <property name="text"> | ||||||
|  |              <string>...</string> | ||||||
|  |             </property> | ||||||
|  |            </widget> | ||||||
|  |           </item> | ||||||
|  |           <item row="0" column="0"> | ||||||
|  |            <widget class="QComboBox" name="inp_bodies_pp"> | ||||||
|  |             <property name="sizePolicy"> | ||||||
|  |              <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> | ||||||
|  |               <horstretch>0</horstretch> | ||||||
|  |               <verstretch>0</verstretch> | ||||||
|  |              </sizepolicy> | ||||||
|  |             </property> | ||||||
|  |             <property name="editable"> | ||||||
|  |              <bool>true</bool> | ||||||
|  |             </property> | ||||||
|  |            </widget> | ||||||
|  |           </item> | ||||||
|  |          </layout> | ||||||
|  |         </item> | ||||||
|  |         <item row="1" column="0"> | ||||||
|  |          <widget class="QLabel" name="lbl_systems_pp"> | ||||||
|  |           <property name="text"> | ||||||
|  |            <string>systemsWithCoordinates.json</string> | ||||||
|  |           </property> | ||||||
|  |          </widget> | ||||||
|  |         </item> | ||||||
|  |         <item row="1" column="1"> | ||||||
|  |          <layout class="QGridLayout" name="gr_systems_pp"> | ||||||
|  |           <item row="0" column="1"> | ||||||
|  |            <widget class="QPushButton" name="btn_systems_browse_pp"> | ||||||
|  |             <property name="text"> | ||||||
|  |              <string>...</string> | ||||||
|  |             </property> | ||||||
|  |            </widget> | ||||||
|  |           </item> | ||||||
|  |           <item row="0" column="0"> | ||||||
|  |            <widget class="QComboBox" name="inp_systems_pp"> | ||||||
|  |             <property name="sizePolicy"> | ||||||
|  |              <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> | ||||||
|  |               <horstretch>0</horstretch> | ||||||
|  |               <verstretch>0</verstretch> | ||||||
|  |              </sizepolicy> | ||||||
|  |             </property> | ||||||
|  |             <property name="editable"> | ||||||
|  |              <bool>true</bool> | ||||||
|  |             </property> | ||||||
|  |            </widget> | ||||||
|  |           </item> | ||||||
|  |          </layout> | ||||||
|  |         </item> | ||||||
|  |         <item row="2" column="0"> | ||||||
|  |          <widget class="QLabel" name="lbl_out_pp"> | ||||||
|  |           <property name="text"> | ||||||
|  |            <string>Output</string> | ||||||
|  |           </property> | ||||||
|  |          </widget> | ||||||
|  |         </item> | ||||||
|  |         <item row="2" column="1"> | ||||||
|  |          <layout class="QGridLayout" name="gr_out_grid_pp"> | ||||||
|  |           <item row="0" column="1"> | ||||||
|  |            <widget class="QPushButton" name="btn_out_browse_pp"> | ||||||
|  |             <property name="sizePolicy"> | ||||||
|  |              <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> | ||||||
|  |               <horstretch>0</horstretch> | ||||||
|  |               <verstretch>0</verstretch> | ||||||
|  |              </sizepolicy> | ||||||
|  |             </property> | ||||||
|  |             <property name="text"> | ||||||
|  |              <string>...</string> | ||||||
|  |             </property> | ||||||
|  |            </widget> | ||||||
|  |           </item> | ||||||
|  |           <item row="0" column="0"> | ||||||
|  |            <widget class="QComboBox" name="inp_out_pp"> | ||||||
|  |             <property name="sizePolicy"> | ||||||
|  |              <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> | ||||||
|  |               <horstretch>0</horstretch> | ||||||
|  |               <verstretch>0</verstretch> | ||||||
|  |              </sizepolicy> | ||||||
|  |             </property> | ||||||
|  |             <property name="editable"> | ||||||
|  |              <bool>true</bool> | ||||||
|  |             </property> | ||||||
|  |            </widget> | ||||||
|  |           </item> | ||||||
|  |          </layout> | ||||||
|  |         </item> | ||||||
|  |         <item row="3" column="0"> | ||||||
|  |          <widget class="QPushButton" name="btn_preprocess"> | ||||||
|  |           <property name="text"> | ||||||
|  |            <string>Preprocess</string> | ||||||
|  |           </property> | ||||||
|  |          </widget> | ||||||
|  |         </item> | ||||||
|  |        </layout> | ||||||
|  |       </widget> | ||||||
|  |       <widget class="QWidget" name="tab_route"> | ||||||
|  |        <attribute name="title"> | ||||||
|  |         <string>Route</string> | ||||||
|  |        </attribute> | ||||||
|  |        <layout class="QFormLayout" name="formLayout_2"> | ||||||
|  |         <item row="0" column="0"> | ||||||
|  |          <widget class="QLabel" name="lbl_sys_lst"> | ||||||
|  |           <property name="text"> | ||||||
|  |            <string>System List</string> | ||||||
|  |           </property> | ||||||
|  |          </widget> | ||||||
|  |         </item> | ||||||
|  |         <item row="0" column="1"> | ||||||
|  |          <layout class="QGridLayout" name="gr_sys"> | ||||||
|  |           <item row="0" column="1"> | ||||||
|  |            <widget class="QPushButton" name="btn_sys_lst_browse"> | ||||||
|  |             <property name="text"> | ||||||
|  |              <string>...</string> | ||||||
|  |             </property> | ||||||
|  |            </widget> | ||||||
|  |           </item> | ||||||
|  |           <item row="0" column="0"> | ||||||
|  |            <widget class="QComboBox" name="inp_sys_lst"> | ||||||
|  |             <property name="sizePolicy"> | ||||||
|  |              <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> | ||||||
|  |               <horstretch>0</horstretch> | ||||||
|  |               <verstretch>0</verstretch> | ||||||
|  |              </sizepolicy> | ||||||
|  |             </property> | ||||||
|  |             <property name="editable"> | ||||||
|  |              <bool>true</bool> | ||||||
|  |             </property> | ||||||
|  |            </widget> | ||||||
|  |           </item> | ||||||
|  |          </layout> | ||||||
|  |         </item> | ||||||
|  |         <item row="1" column="0"> | ||||||
|  |          <widget class="QPushButton" name="btn_add"> | ||||||
|  |           <property name="text"> | ||||||
|  |            <string>Search+Add</string> | ||||||
|  |           </property> | ||||||
|  |          </widget> | ||||||
|  |         </item> | ||||||
|  |         <item row="1" column="1"> | ||||||
|  |          <widget class="QLineEdit" name="inp_sys"/> | ||||||
|  |         </item> | ||||||
|  |         <item row="3" column="0"> | ||||||
|  |          <widget class="QPushButton" name="btn_rm"> | ||||||
|  |           <property name="text"> | ||||||
|  |            <string>Remove</string> | ||||||
|  |           </property> | ||||||
|  |          </widget> | ||||||
|  |         </item> | ||||||
|  |         <item row="3" column="1"> | ||||||
|  |          <layout class="QGridLayout" name="gr_mode"> | ||||||
|  |           <item row="0" column="1"> | ||||||
|  |            <widget class="QRadioButton" name="rd_comp"> | ||||||
|  |             <property name="text"> | ||||||
|  |              <string>Compute Route</string> | ||||||
|  |             </property> | ||||||
|  |             <property name="checked"> | ||||||
|  |              <bool>true</bool> | ||||||
|  |             </property> | ||||||
|  |            </widget> | ||||||
|  |           </item> | ||||||
|  |           <item row="0" column="2"> | ||||||
|  |            <widget class="QRadioButton" name="rd_precomp"> | ||||||
|  |             <property name="text"> | ||||||
|  |              <string>Precompute Graph</string> | ||||||
|  |             </property> | ||||||
|  |            </widget> | ||||||
|  |           </item> | ||||||
|  |          </layout> | ||||||
|  |         </item> | ||||||
|  |         <item row="4" column="0"> | ||||||
|  |          <widget class="QPushButton" name="btn_permute"> | ||||||
|  |           <property name="text"> | ||||||
|  |            <string>Permute</string> | ||||||
|  |           </property> | ||||||
|  |          </widget> | ||||||
|  |         </item> | ||||||
|  |         <item row="4" column="1"> | ||||||
|  |          <widget class="QCheckBox" name="chk_permute_keep"> | ||||||
|  |           <property name="sizePolicy"> | ||||||
|  |            <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> | ||||||
|  |             <horstretch>0</horstretch> | ||||||
|  |             <verstretch>0</verstretch> | ||||||
|  |            </sizepolicy> | ||||||
|  |           </property> | ||||||
|  |           <property name="text"> | ||||||
|  |            <string>Keep endpoints (No, first only, yes)</string> | ||||||
|  |           </property> | ||||||
|  |           <property name="tristate"> | ||||||
|  |            <bool>true</bool> | ||||||
|  |           </property> | ||||||
|  |          </widget> | ||||||
|  |         </item> | ||||||
|  |         <item row="5" column="0" colspan="2"> | ||||||
|  |          <widget class="QTreeWidget" name="lst_sys"> | ||||||
|  |           <property name="sizePolicy"> | ||||||
|  |            <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||||||
|  |             <horstretch>0</horstretch> | ||||||
|  |             <verstretch>0</verstretch> | ||||||
|  |            </sizepolicy> | ||||||
|  |           </property> | ||||||
|  |           <property name="minimumSize"> | ||||||
|  |            <size> | ||||||
|  |             <width>0</width> | ||||||
|  |             <height>0</height> | ||||||
|  |            </size> | ||||||
|  |           </property> | ||||||
|  |           <property name="dragEnabled"> | ||||||
|  |            <bool>true</bool> | ||||||
|  |           </property> | ||||||
|  |           <property name="dragDropOverwriteMode"> | ||||||
|  |            <bool>false</bool> | ||||||
|  |           </property> | ||||||
|  |           <property name="dragDropMode"> | ||||||
|  |            <enum>QAbstractItemView::InternalMove</enum> | ||||||
|  |           </property> | ||||||
|  |           <property name="defaultDropAction"> | ||||||
|  |            <enum>Qt::MoveAction</enum> | ||||||
|  |           </property> | ||||||
|  |           <property name="alternatingRowColors"> | ||||||
|  |            <bool>true</bool> | ||||||
|  |           </property> | ||||||
|  |           <property name="selectionMode"> | ||||||
|  |            <enum>QAbstractItemView::ExtendedSelection</enum> | ||||||
|  |           </property> | ||||||
|  |           <property name="selectionBehavior"> | ||||||
|  |            <enum>QAbstractItemView::SelectRows</enum> | ||||||
|  |           </property> | ||||||
|  |           <column> | ||||||
|  |            <property name="text"> | ||||||
|  |             <string notr="true">1</string> | ||||||
|  |            </property> | ||||||
|  |           </column> | ||||||
|  |          </widget> | ||||||
|  |         </item> | ||||||
|  |         <item row="6" column="1"> | ||||||
|  |          <widget class="QDoubleSpinBox" name="sb_range"/> | ||||||
|  |         </item> | ||||||
|  |         <item row="6" column="0"> | ||||||
|  |          <widget class="QLabel" name="lbl_range"> | ||||||
|  |           <property name="text"> | ||||||
|  |            <string>Jump Range (Ly)</string> | ||||||
|  |           </property> | ||||||
|  |          </widget> | ||||||
|  |         </item> | ||||||
|  |         <item row="7" column="0" colspan="2"> | ||||||
|  |          <layout class="QGridLayout" name="gr_opts"> | ||||||
|  |           <item row="0" column="2"> | ||||||
|  |            <widget class="QComboBox" name="cmb_mode"> | ||||||
|  |             <property name="currentText"> | ||||||
|  |              <string>Breadth-First Search</string> | ||||||
|  |             </property> | ||||||
|  |             <item> | ||||||
|  |              <property name="text"> | ||||||
|  |               <string>Breadth-First Search</string> | ||||||
|  |              </property> | ||||||
|  |             </item> | ||||||
|  |             <item> | ||||||
|  |              <property name="text"> | ||||||
|  |               <string>Greedy-Search</string> | ||||||
|  |              </property> | ||||||
|  |             </item> | ||||||
|  |             <item> | ||||||
|  |              <property name="text"> | ||||||
|  |               <string>A*-Search</string> | ||||||
|  |              </property> | ||||||
|  |             </item> | ||||||
|  |            </widget> | ||||||
|  |           </item> | ||||||
|  |           <item row="1" column="1"> | ||||||
|  |            <widget class="QLabel" name="lbl_greedyness"> | ||||||
|  |             <property name="enabled"> | ||||||
|  |              <bool>true</bool> | ||||||
|  |             </property> | ||||||
|  |             <property name="text"> | ||||||
|  |              <string>Greedyness Factor</string> | ||||||
|  |             </property> | ||||||
|  |            </widget> | ||||||
|  |           </item> | ||||||
|  |           <item row="0" column="3"> | ||||||
|  |            <widget class="QCheckBox" name="chk_primary"> | ||||||
|  |             <property name="text"> | ||||||
|  |              <string>Primary Stars Only</string> | ||||||
|  |             </property> | ||||||
|  |            </widget> | ||||||
|  |           </item> | ||||||
|  |           <item row="1" column="2" colspan="2"> | ||||||
|  |            <widget class="QSlider" name="sld_greedyness"> | ||||||
|  |             <property name="maximum"> | ||||||
|  |              <number>100</number> | ||||||
|  |             </property> | ||||||
|  |             <property name="pageStep"> | ||||||
|  |              <number>10</number> | ||||||
|  |             </property> | ||||||
|  |             <property name="value"> | ||||||
|  |              <number>50</number> | ||||||
|  |             </property> | ||||||
|  |             <property name="orientation"> | ||||||
|  |              <enum>Qt::Horizontal</enum> | ||||||
|  |             </property> | ||||||
|  |             <property name="tickPosition"> | ||||||
|  |              <enum>QSlider::TicksBelow</enum> | ||||||
|  |             </property> | ||||||
|  |             <property name="tickInterval"> | ||||||
|  |              <number>10</number> | ||||||
|  |             </property> | ||||||
|  |            </widget> | ||||||
|  |           </item> | ||||||
|  |           <item row="0" column="1"> | ||||||
|  |            <widget class="QLabel" name="lbl_mode"> | ||||||
|  |             <property name="text"> | ||||||
|  |              <string>Mode</string> | ||||||
|  |             </property> | ||||||
|  |            </widget> | ||||||
|  |           </item> | ||||||
|  |          </layout> | ||||||
|  |         </item> | ||||||
|  |         <item row="8" column="0"> | ||||||
|  |          <widget class="QPushButton" name="btn_go"> | ||||||
|  |           <property name="text"> | ||||||
|  |            <string>GO!</string> | ||||||
|  |           </property> | ||||||
|  |           <property name="flat"> | ||||||
|  |            <bool>false</bool> | ||||||
|  |           </property> | ||||||
|  |          </widget> | ||||||
|  |         </item> | ||||||
|  |        </layout> | ||||||
|  |       </widget> | ||||||
|  |       <widget class="QWidget" name="tab_log"> | ||||||
|  |        <attribute name="title"> | ||||||
|  |         <string>Log</string> | ||||||
|  |        </attribute> | ||||||
|  |        <layout class="QGridLayout" name="gridLayout_3"> | ||||||
|  |         <item row="0" column="0"> | ||||||
|  |          <widget class="QTextEdit" name="txt_log"> | ||||||
|  |           <property name="enabled"> | ||||||
|  |            <bool>true</bool> | ||||||
|  |           </property> | ||||||
|  |           <property name="frameShadow"> | ||||||
|  |            <enum>QFrame::Sunken</enum> | ||||||
|  |           </property> | ||||||
|  |           <property name="lineWidth"> | ||||||
|  |            <number>1</number> | ||||||
|  |           </property> | ||||||
|  |           <property name="readOnly"> | ||||||
|  |            <bool>true</bool> | ||||||
|  |           </property> | ||||||
|  |           <property name="acceptRichText"> | ||||||
|  |            <bool>false</bool> | ||||||
|  |           </property> | ||||||
|  |          </widget> | ||||||
|  |         </item> | ||||||
|  |        </layout> | ||||||
|  |       </widget> | ||||||
|  |      </widget> | ||||||
|  |     </item> | ||||||
|  |    </layout> | ||||||
|  |   </widget> | ||||||
|  |   <widget class="QMenuBar" name="menu"> | ||||||
|  |    <property name="geometry"> | ||||||
|  |     <rect> | ||||||
|  |      <x>0</x> | ||||||
|  |      <y>0</y> | ||||||
|  |      <width>577</width> | ||||||
|  |      <height>21</height> | ||||||
|  |     </rect> | ||||||
|  |    </property> | ||||||
|  |    <widget class="QMenu" name="menu_file"> | ||||||
|  |     <property name="title"> | ||||||
|  |      <string>File</string> | ||||||
|  |     </property> | ||||||
|  |     <addaction name="menu_act_quit"/> | ||||||
|  |    </widget> | ||||||
|  |    <addaction name="menu_file"/> | ||||||
|  |   </widget> | ||||||
|  |   <widget class="QStatusBar" name="bar_status"/> | ||||||
|  |   <action name="menu_act_quit"> | ||||||
|  |    <property name="text"> | ||||||
|  |     <string>Quit</string> | ||||||
|  |    </property> | ||||||
|  |    <property name="shortcut"> | ||||||
|  |     <string>Ctrl+Q</string> | ||||||
|  |    </property> | ||||||
|  |   </action> | ||||||
|  |  </widget> | ||||||
|  |  <tabstops> | ||||||
|  |   <tabstop>rd_comp</tabstop> | ||||||
|  |   <tabstop>cmb_mode</tabstop> | ||||||
|  |   <tabstop>chk_primary</tabstop> | ||||||
|  |   <tabstop>sld_greedyness</tabstop> | ||||||
|  |   <tabstop>rd_precomp</tabstop> | ||||||
|  |  </tabstops> | ||||||
|  |  <resources/> | ||||||
|  |  <connections/> | ||||||
|  | </ui> | ||||||
							
								
								
									
										2
									
								
								pyproject.toml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								pyproject.toml
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,2 @@ | ||||||
|  | [build-system] | ||||||
|  | requires = ["setuptools", "wheel", "setuptools-rust"] | ||||||
							
								
								
									
										2
									
								
								rust/.cargo/config
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								rust/.cargo/config
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,2 @@ | ||||||
|  | [build] | ||||||
|  | rustflags = ["-C", "target-cpu=native"] | ||||||
							
								
								
									
										2091
									
								
								rust/Cargo.lock
									
										
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										2091
									
								
								rust/Cargo.lock
									
										
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										34
									
								
								rust/Cargo.toml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								rust/Cargo.toml
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,34 @@ | ||||||
|  | [package] | ||||||
|  | name = "ed_lrr" | ||||||
|  | version = "0.1.0" | ||||||
|  | authors = ["Daniel Seiller <earthnuker@gmail.com>"] | ||||||
|  | edition = "2018" | ||||||
|  | repository = "https://gitlab.com/Earthnuker/ed_lrr.git" | ||||||
|  | license = "WTFPL" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | [lib] | ||||||
|  | crate-type = ["cdylib"] | ||||||
|  | 
 | ||||||
|  | [profile.release] | ||||||
|  | # debug=true | ||||||
|  | 
 | ||||||
|  | [dependencies] | ||||||
|  | csv = "1.1.1" | ||||||
|  | serde = "1.0.94" | ||||||
|  | serde_derive = "1.0.94" | ||||||
|  | rstar = {version="0.4.0"} | ||||||
|  | humantime = "1.2.0" | ||||||
|  | structopt = "0.2.18" | ||||||
|  | permutohedron = "0.2.4" | ||||||
|  | serde_json = "1.0.40" | ||||||
|  | indicatif = "0.11.0" | ||||||
|  | fnv = "1.0.6" | ||||||
|  | bincode = "1.1.4" | ||||||
|  | sha3 = "0.8.2" | ||||||
|  | byteorder = "1.3.2" | ||||||
|  | reqwest = "0.9.18" | ||||||
|  | 
 | ||||||
|  | [dependencies.pyo3] | ||||||
|  | version = "0.7.0" | ||||||
|  | features = ["extension-module"] | ||||||
							
								
								
									
										38
									
								
								rust/src/common.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								rust/src/common.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,38 @@ | ||||||
|  | use serde::{Deserialize, Serialize}; | ||||||
|  | #[derive(Debug, Clone, Serialize, Deserialize)] | ||||||
|  | pub struct SystemSerde { | ||||||
|  |     pub id: u32, | ||||||
|  |     pub star_type: String, | ||||||
|  |     pub system: String, | ||||||
|  |     pub body: String, | ||||||
|  |     pub mult: f32, | ||||||
|  |     pub distance: u32, | ||||||
|  |     pub x: f32, | ||||||
|  |     pub y: f32, | ||||||
|  |     pub z: f32, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl SystemSerde { | ||||||
|  |     pub fn build(&self) -> System { | ||||||
|  |         System { | ||||||
|  |             id: self.id, | ||||||
|  |             star_type: self.star_type.clone(), | ||||||
|  |             system: self.system.clone(), | ||||||
|  |             body: self.body.clone(), | ||||||
|  |             mult: self.mult, | ||||||
|  |             distance: self.distance, | ||||||
|  |             pos: [self.x, self.y, self.z], | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Debug, Clone, Deserialize, Serialize)] | ||||||
|  | pub struct System { | ||||||
|  |     pub id: u32, | ||||||
|  |     pub star_type: String, | ||||||
|  |     pub system: String, | ||||||
|  |     pub body: String, | ||||||
|  |     pub mult: f32, | ||||||
|  |     pub distance: u32, | ||||||
|  |     pub pos: [f32; 3], | ||||||
|  | } | ||||||
							
								
								
									
										63
									
								
								rust/src/download.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								rust/src/download.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,63 @@ | ||||||
|  | use indicatif::{MultiProgress, ProgressBar, ProgressStyle}; | ||||||
|  | use std::fs::File; | ||||||
|  | use std::io; | ||||||
|  | use std::path::PathBuf; | ||||||
|  | use structopt::StructOpt; | ||||||
|  | 
 | ||||||
|  | #[derive(Debug, StructOpt, Clone)] | ||||||
|  | pub struct DownloadOpts { | ||||||
|  |     #[structopt(
 | ||||||
|  |         long = "bodies", | ||||||
|  |         default_value = "https://www.edsm.net/dump/bodies.json" | ||||||
|  |     )] | ||||||
|  |     /// Url to bodies.json
 | ||||||
|  |     bodies_url: String, | ||||||
|  |     #[structopt(
 | ||||||
|  |         long = "systems", | ||||||
|  |         default_value = "https://www.edsm.net/dump/systemsWithCoordinates.json" | ||||||
|  |     )] | ||||||
|  |     /// Url to systemsWithCoordinates.json
 | ||||||
|  |     systems_url: String, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn fetch_url(url: &str, prog_bar: &ProgressBar) -> std::io::Result<()> { | ||||||
|  |     let outfile = url.split('/').last().unwrap(); | ||||||
|  |     let template = format!("{} {}", "[{elapsed_precise}] {binary_bytes}", outfile); | ||||||
|  |     prog_bar.set_style(ProgressStyle::default_bar().template(&template)); | ||||||
|  | 
 | ||||||
|  |     let client = reqwest::Client::builder().gzip(true).build().unwrap(); | ||||||
|  |     let resp = client.get(url).send().unwrap(); | ||||||
|  |     let target_path = PathBuf::from(format!("dumps/{}", outfile)); | ||||||
|  |     if target_path.exists() { | ||||||
|  |         eprintln!("Error: Target {} exists!", outfile); | ||||||
|  |         return Ok(()); | ||||||
|  |     } | ||||||
|  |     let mut target = File::create(target_path)?; | ||||||
|  |     io::copy(&mut prog_bar.wrap_read(resp), &mut target).unwrap(); | ||||||
|  |     prog_bar.finish(); | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub fn download(opts: DownloadOpts) -> std::io::Result<()> { | ||||||
|  |     let mut threads = Vec::new(); | ||||||
|  |     let m = MultiProgress::new(); | ||||||
|  |     { | ||||||
|  |         let opts = opts.clone(); | ||||||
|  |         let pb = m.add(ProgressBar::new(0)); | ||||||
|  |         threads.push(std::thread::spawn(move || { | ||||||
|  |             fetch_url(&opts.bodies_url, &pb).unwrap(); | ||||||
|  |         })); | ||||||
|  |     }; | ||||||
|  |     { | ||||||
|  |         let opts = opts.clone(); | ||||||
|  |         let pb = m.add(ProgressBar::new(0)); | ||||||
|  |         threads.push(std::thread::spawn(move || { | ||||||
|  |             fetch_url(&opts.systems_url, &pb).unwrap(); | ||||||
|  |         })); | ||||||
|  |     } | ||||||
|  |     m.join_and_clear().unwrap(); | ||||||
|  |     for th in threads { | ||||||
|  |         th.join().unwrap(); | ||||||
|  |     } | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
							
								
								
									
										66
									
								
								rust/src/lib.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								rust/src/lib.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,66 @@ | ||||||
|  | mod common; | ||||||
|  | mod download; | ||||||
|  | mod preprocess; | ||||||
|  | mod route; | ||||||
|  | use std::collections::HashMap; | ||||||
|  | use pyo3::prelude::*; | ||||||
|  | use pyo3::types::PyDict; | ||||||
|  | use std::path::PathBuf; | ||||||
|  | 
 | ||||||
|  | #[pymodule] | ||||||
|  | pub fn _ed_lrr(py: Python, m: &PyModule) -> PyResult<()> { | ||||||
|  |     /// Test
 | ||||||
|  |     #[pyfn(m,"test")] | ||||||
|  |     fn test(py:Python,o:PyObject) -> PyResult<()> { | ||||||
|  |         println!("OBJ: {:?}",o); | ||||||
|  |         return Ok(()); | ||||||
|  |     } | ||||||
|  |     
 | ||||||
|  |     /// download(systems_url,systems_file, bodies_url, bodies_file, callback)
 | ||||||
|  |     /// --
 | ||||||
|  |     ///
 | ||||||
|  |     /// Download bodies.json and systemsWithCoordinates.json
 | ||||||
|  |     #[pyfn(m, "download")] | ||||||
|  |     fn download(py: Python, systems_url: String, systems_file: String, bodies_url:String,bodies_file:String,callback: PyObject) -> PyResult<PyObject> { | ||||||
|  |         let state = PyDict::new(py); | ||||||
|  |         state.set_item("systems_url", systems_url)?; | ||||||
|  |         state.set_item("systems_file", systems_file)?; | ||||||
|  |         state.set_item("bodies_url", bodies_url)?; | ||||||
|  |         state.set_item("bodies_file", bodies_file)?; | ||||||
|  |         state.set_item("callback", callback)?; | ||||||
|  |         return Ok(state.to_object(py)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// preprocess(infile_systems, infile_bodies, outfile, callback)
 | ||||||
|  |     /// -- 
 | ||||||
|  |     ///
 | ||||||
|  |     /// Preprocess bodies.json and systemsWithCoordinates.json into stars.csv
 | ||||||
|  |     #[pyfn(m, "preprocess")] | ||||||
|  |     fn preprocess(py: Python, infile_systems: String, infile_bodies: String, outfile:String,callback: PyObject) -> PyResult<PyObject> { | ||||||
|  |         let state = PyDict::new(py); | ||||||
|  |         state.set_item("infile_systems", infile_systems)?; | ||||||
|  |         state.set_item("infile_bodies", infile_bodies)?; | ||||||
|  |         state.set_item("outfile", outfile)?; | ||||||
|  |         state.set_item("callback", callback)?; | ||||||
|  |         return Ok(state.to_object(py)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// route(infile, source, dest, range, mode, greedyness, precomp, callback)
 | ||||||
|  |     /// --
 | ||||||
|  |     ///
 | ||||||
|  |     /// Compute a Route using the suplied parameters
 | ||||||
|  |     #[pyfn(m, "route")] | ||||||
|  |     fn route(py: Python, infile: String, source: String, dest:String, range: f32, mode: String,greedyness: Option<f32>, precomp: Option<String>,callback: PyObject) -> PyResult<PyObject> { | ||||||
|  |         let state = PyDict::new(py); | ||||||
|  |         state.set_item("infile", infile)?; | ||||||
|  |         state.set_item("source", source)?; | ||||||
|  |         state.set_item("dest", dest)?; | ||||||
|  |         state.set_item("range", range)?; | ||||||
|  |         state.set_item("mode", mode)?; | ||||||
|  |         state.set_item("greedyness", greedyness)?; | ||||||
|  |         state.set_item("precomp", precomp)?; | ||||||
|  |         state.set_item("callback", callback)?; | ||||||
|  |         return Ok(state.to_object(py)); | ||||||
|  |     } | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
							
								
								
									
										220
									
								
								rust/src/preprocess.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										220
									
								
								rust/src/preprocess.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,220 @@ | ||||||
|  | use crate::common::SystemSerde; | ||||||
|  | use fnv::FnvHashMap; | ||||||
|  | use humantime::format_duration; | ||||||
|  | use indicatif::{ProgressBar, ProgressStyle}; | ||||||
|  | use serde::Deserialize; | ||||||
|  | use serde_json::Result; | ||||||
|  | use std::fs::File; | ||||||
|  | use std::io::Seek; | ||||||
|  | use std::io::{BufRead, BufReader, BufWriter, SeekFrom}; | ||||||
|  | use std::path::PathBuf; | ||||||
|  | use std::str; | ||||||
|  | use std::time::Instant; | ||||||
|  | use structopt::StructOpt; | ||||||
|  | 
 | ||||||
|  | #[derive(Debug, StructOpt)] | ||||||
|  | pub struct PreprocessOpts { | ||||||
|  |     #[structopt(short, long = "bodies", default_value = "dumps/bodies.json")] | ||||||
|  |     /// Path to bodies.json
 | ||||||
|  |     pub bodies: PathBuf, | ||||||
|  |     #[structopt(
 | ||||||
|  |         short, | ||||||
|  |         long = "systems", | ||||||
|  |         default_value = "dumps/systemsWithCoordinates.json" | ||||||
|  |     )] | ||||||
|  |     /// Path to systemsWithCoordinates.json
 | ||||||
|  |     pub systems: PathBuf, | ||||||
|  |     #[structopt(default_value = "stars")] | ||||||
|  |     /// outfile prefix
 | ||||||
|  |     pub prefix: String, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Debug, Deserialize)] | ||||||
|  | #[allow(non_snake_case)] | ||||||
|  | struct Body { | ||||||
|  |     name: String, | ||||||
|  |     subType: String, | ||||||
|  |     #[serde(rename = "type")] | ||||||
|  |     body_type: String, | ||||||
|  |     systemId: i32, | ||||||
|  |     systemId64: i64, | ||||||
|  |     #[serde(rename = "distanceToArrival")] | ||||||
|  |     distance: u32, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Debug, Deserialize)] | ||||||
|  | struct Coords { | ||||||
|  |     x: f32, | ||||||
|  |     y: f32, | ||||||
|  |     z: f32, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Debug, Deserialize)] | ||||||
|  | struct System { | ||||||
|  |     id: i32, | ||||||
|  |     id64: i64, | ||||||
|  |     name: String, | ||||||
|  |     coords: Coords, | ||||||
|  |     date: String, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Debug, StructOpt)] | ||||||
|  | #[structopt(
 | ||||||
|  |     name = "ed_lrr_pp", | ||||||
|  |     about = "Preprocessor for Elite: Dangerous Long-Range Router", | ||||||
|  |     rename_all = "snake_case" | ||||||
|  | )] | ||||||
|  | /// Preprocess data for ed_lrr
 | ||||||
|  | struct Opt { | ||||||
|  |     #[structopt(short, long = "bodies")] | ||||||
|  |     /// Path to bodies.json
 | ||||||
|  |     bodies: PathBuf, | ||||||
|  |     #[structopt(short, long = "systems")] | ||||||
|  |     /// Path to systemsWithCoordinates.json
 | ||||||
|  |     systems: PathBuf, | ||||||
|  |     #[structopt(default_value = "stars")] | ||||||
|  |     /// outfile prefix
 | ||||||
|  |     prefix: String, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn get_mult(star_type: &str) -> f32 { | ||||||
|  |     if star_type.contains("White Dwarf") { | ||||||
|  |         return 1.5; | ||||||
|  |     } | ||||||
|  |     if star_type.contains("Neutron") { | ||||||
|  |         return 4.0; | ||||||
|  |     } | ||||||
|  |     1.0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn process(path: &PathBuf, func: &mut dyn for<'r> FnMut(&'r str) -> ()) -> std::io::Result<()> { | ||||||
|  |     let mut cnt = 0; | ||||||
|  |     let mut buffer = String::new(); | ||||||
|  |     let t_start = Instant::now(); | ||||||
|  |     let fh = File::open(path)?; | ||||||
|  |     let prog_bar = ProgressBar::new(fh.metadata()?.len()); | ||||||
|  |     prog_bar.set_style( | ||||||
|  |         ProgressStyle::default_bar() | ||||||
|  |             .template( | ||||||
|  |                 "[{elapsed_precise}/{eta_precise}]{spinner} [{wide_bar}] {binary_bytes}/{binary_total_bytes} ({percent}%)", | ||||||
|  |             ) | ||||||
|  |             .progress_chars("#9876543210 ") | ||||||
|  |             .tick_chars("/-\\|"), | ||||||
|  |     ); | ||||||
|  |     prog_bar.set_draw_delta(1024 * 1024); | ||||||
|  |     let mut reader = BufReader::new(fh); | ||||||
|  |     println!("Loading {} ...", path.to_str().unwrap()); | ||||||
|  |     while let Ok(n) = reader.read_line(&mut buffer) { | ||||||
|  |         if n == 0 { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         buffer = buffer.trim_end().trim_end_matches(|c| c == ',').to_string(); | ||||||
|  |         if !buffer.is_empty() { | ||||||
|  |             func(&buffer); | ||||||
|  |         } | ||||||
|  |         prog_bar.set_position(reader.seek(SeekFrom::Current(0)).unwrap()); | ||||||
|  |         cnt += 1; | ||||||
|  |         buffer.clear(); | ||||||
|  |     } | ||||||
|  |     prog_bar.finish_and_clear(); | ||||||
|  |     println!( | ||||||
|  |         "Processed {} lines in {} ...", | ||||||
|  |         cnt, | ||||||
|  |         format_duration(t_start.elapsed()) | ||||||
|  |     ); | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn process_systems(path: &PathBuf) -> FnvHashMap<i32, System> { | ||||||
|  |     let mut ret = FnvHashMap::default(); | ||||||
|  |     process(path, &mut |line| { | ||||||
|  |         let sys_res: Result<System> = serde_json::from_str(&line); | ||||||
|  |         if let Ok(sys) = sys_res { | ||||||
|  |             ret.insert(sys.id, sys); | ||||||
|  |         } else { | ||||||
|  |             eprintln!("\nError parsing: {}\n\t{:?}\n", line, sys_res.unwrap_err()); | ||||||
|  |         } | ||||||
|  |     }) | ||||||
|  |     .unwrap(); | ||||||
|  |     ret | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn build_index(path: &PathBuf) -> std::io::Result<()> { | ||||||
|  |     let mut wtr = BufWriter::new(File::create(path.with_extension("idx"))?); | ||||||
|  |     let mut idx: Vec<u64> = Vec::new(); | ||||||
|  |     let mut records = (csv::Reader::from_path(path)?).into_deserialize::<SystemSerde>(); | ||||||
|  |     loop { | ||||||
|  |         idx.push(records.reader().position().byte()); | ||||||
|  |         if records.next().is_none() { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     bincode::serialize_into(&mut wtr, &idx).unwrap(); | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn process_bodies( | ||||||
|  |     path: &PathBuf, | ||||||
|  |     out_prefix: &str, | ||||||
|  |     systems: &mut FnvHashMap<i32, System>, | ||||||
|  | ) -> std::io::Result<()> { | ||||||
|  |     let out_path = PathBuf::from(format!("{}.csv", out_prefix)); | ||||||
|  |     println!( | ||||||
|  |         "Processing {} into {} ...", | ||||||
|  |         path.to_str().unwrap(), | ||||||
|  |         out_path.to_str().unwrap(), | ||||||
|  |     ); | ||||||
|  |     let mut n: u32 = 0; | ||||||
|  |     let mut wtr = csv::Writer::from_path(out_path)?; | ||||||
|  |     process(path, &mut |line| { | ||||||
|  |         if !line.contains("Star") { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         let body_res: Result<Body> = serde_json::from_str(&line); | ||||||
|  |         if let Ok(body) = body_res { | ||||||
|  |             if !body.body_type.contains("Star") { | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |             if let Some(sys) = systems.get(&body.systemId) { | ||||||
|  |                 let sub_type = body.subType; | ||||||
|  |                 let mult = get_mult(&sub_type); | ||||||
|  |                 let sys_name = sys.name.clone(); | ||||||
|  |                 let rec = SystemSerde { | ||||||
|  |                     id: n, | ||||||
|  |                     star_type: sub_type, | ||||||
|  |                     system: sys_name, | ||||||
|  |                     body: body.name, | ||||||
|  |                     mult, | ||||||
|  |                     distance: body.distance, | ||||||
|  |                     x: sys.coords.x, | ||||||
|  |                     y: sys.coords.y, | ||||||
|  |                     z: sys.coords.z, | ||||||
|  |                 }; | ||||||
|  |                 wtr.serialize(rec).unwrap(); | ||||||
|  |                 n += 1; | ||||||
|  |             }; | ||||||
|  |         } else { | ||||||
|  |             eprintln!("\nError parsing: {}\n\t{:?}\n", line, body_res.unwrap_err()); | ||||||
|  |         } | ||||||
|  |     }) | ||||||
|  |     .unwrap(); | ||||||
|  |     println!("Total Systems: {}", n); | ||||||
|  |     systems.clear(); | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub fn preprocess_files(opts: PreprocessOpts) -> std::io::Result<()> { | ||||||
|  |     let out_path = PathBuf::from(format!("{}.csv", &opts.prefix)); | ||||||
|  |     if !out_path.exists() { | ||||||
|  |         let mut systems = process_systems(&opts.systems); | ||||||
|  |         process_bodies(&opts.bodies, &opts.prefix, &mut systems)?; | ||||||
|  |     } else { | ||||||
|  |         println!( | ||||||
|  |             "File '{}' exists, not overwriting it", | ||||||
|  |             out_path.to_str().unwrap() | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |     println!("Building index..."); | ||||||
|  |     println!("Index result: {:?}", build_index(&out_path)); | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
							
								
								
									
										879
									
								
								rust/src/route.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										879
									
								
								rust/src/route.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,879 @@ | ||||||
|  | use core::cmp::Ordering; | ||||||
|  | use csv::StringRecord; | ||||||
|  | use fnv::{FnvHashMap, FnvHashSet}; | ||||||
|  | use humantime::format_duration; | ||||||
|  | use permutohedron::LexicalPermutation; | ||||||
|  | use rstar::{PointDistance, RTree, RTreeObject, AABB}; | ||||||
|  | use sha3::{Digest, Sha3_256}; | ||||||
|  | use std::collections::VecDeque; | ||||||
|  | use std::fs::File; | ||||||
|  | use std::hash::{Hash, Hasher}; | ||||||
|  | use std::io::Seek; | ||||||
|  | use std::io::{BufRead, BufReader, BufWriter, Write}; | ||||||
|  | use std::path::PathBuf; | ||||||
|  | use std::str::FromStr; | ||||||
|  | use std::time::Instant; | ||||||
|  | use structopt::StructOpt; | ||||||
|  | 
 | ||||||
|  | use crate::common::{System, SystemSerde}; | ||||||
|  | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub struct SearchState { | ||||||
|  |     pub mode: String, | ||||||
|  |     pub depth: usize, | ||||||
|  |     pub queue_size: usize, | ||||||
|  |     pub d_rem: f64, | ||||||
|  |     pub prc_done: f64, | ||||||
|  |     pub n_seen: usize, | ||||||
|  |     pub prc_seen: f64 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub struct RouteOpts { | ||||||
|  |     pub range: Option<f32>, | ||||||
|  |     pub file_path: PathBuf, | ||||||
|  |     pub precomp_file: Option<PathBuf>, | ||||||
|  |     pub precompute: bool, | ||||||
|  |     pub permute: bool, | ||||||
|  |     pub primary: bool, | ||||||
|  |     pub full_permute: bool, | ||||||
|  |     pub factor: Option<f32>, | ||||||
|  |     pub mode: Mode, | ||||||
|  |     pub systems: Vec<String>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub enum Mode { | ||||||
|  |     BFS, | ||||||
|  |     Greedy, | ||||||
|  |     AStar, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl FromStr for Mode { | ||||||
|  |     type Err = String; | ||||||
|  |     fn from_str(s: &str) -> Result<Mode, String> { | ||||||
|  |         match s { | ||||||
|  |             "bfs" => Ok(Mode::BFS), | ||||||
|  |             "greedy" => Ok(Mode::Greedy), | ||||||
|  |             "astar" => Ok(Mode::AStar), | ||||||
|  |             _ => Err("Invalid Mode".to_string()), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn dist2(p1: &[f32; 3], p2: &[f32; 3]) -> f32 { | ||||||
|  |     let dx = p1[0] - p2[0]; | ||||||
|  |     let dy = p1[1] - p2[1]; | ||||||
|  |     let dz = p1[2] - p2[2]; | ||||||
|  | 
 | ||||||
|  |     dx * dx + dy * dy + dz * dz | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn dist(p1: &[f32; 3], p2: &[f32; 3]) -> f32 { | ||||||
|  |     dist2(p1, p2).sqrt() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn fcmp(a: f32, b: f32) -> Ordering { | ||||||
|  |     match (a, b) { | ||||||
|  |         (x, y) if x.is_nan() && y.is_nan() => Ordering::Equal, | ||||||
|  |         (x, _) if x.is_nan() => Ordering::Greater, | ||||||
|  |         (_, y) if y.is_nan() => Ordering::Less, | ||||||
|  |         (..) => a.partial_cmp(&b).unwrap(), | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl System { | ||||||
|  |     pub fn dist2(&self, p: &[f32; 3]) -> f32 { | ||||||
|  |         dist2(&self.pos, p) | ||||||
|  |     } | ||||||
|  |     pub fn distp(&self, p: &System) -> f32 { | ||||||
|  |         dist(&self.pos, &p.pos) | ||||||
|  |     } | ||||||
|  |     pub fn distp2(&self, p: &System) -> f32 { | ||||||
|  |         self.dist2(&p.pos) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | impl PartialEq for System { | ||||||
|  |     fn eq(&self, other: &Self) -> bool { | ||||||
|  |         self.id == other.id | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Eq for System {} | ||||||
|  | 
 | ||||||
|  | impl Hash for System { | ||||||
|  |     fn hash<H: Hasher>(&self, state: &mut H) { | ||||||
|  |         self.id.hash(state); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl RTreeObject for System { | ||||||
|  |     type Envelope = AABB<[f32; 3]>; | ||||||
|  | 
 | ||||||
|  |     fn envelope(&self) -> Self::Envelope { | ||||||
|  |         AABB::from_point(self.pos) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl PointDistance for System { | ||||||
|  |     fn distance_2(&self, point: &[f32; 3]) -> f32 { | ||||||
|  |         self.dist2(&point) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn hash_file(path: &PathBuf) -> Vec<u8> { | ||||||
|  |     let mut hash_reader = BufReader::new(File::open(path).unwrap()); | ||||||
|  |     let mut hasher = Sha3_256::new(); | ||||||
|  |     std::io::copy(&mut hash_reader, &mut hasher).unwrap(); | ||||||
|  |     hasher.result().iter().copied().collect() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct LineCache { | ||||||
|  |     cache: Vec<u64>, | ||||||
|  |     file: BufReader<File>, | ||||||
|  |     header: Option<StringRecord>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl LineCache { | ||||||
|  |     pub fn new(path: &PathBuf) -> Option<Self> { | ||||||
|  |         let idx_path = path.with_extension("idx"); | ||||||
|  |         let t_load = Instant::now(); | ||||||
|  |         println!("Loading Index from {}", idx_path.to_str().unwrap()); | ||||||
|  |         let cache = | ||||||
|  |             bincode::deserialize_from(&mut BufReader::new(File::open(idx_path).ok()?)).ok()?; | ||||||
|  |         let mut reader = BufReader::new(File::open(path).ok()?); | ||||||
|  |         let header = Self::read_record(&mut reader); | ||||||
|  |         let ret = Self { | ||||||
|  |             file: reader, | ||||||
|  |             cache, | ||||||
|  |             header, | ||||||
|  |         }; | ||||||
|  |         println!("Done in {}!", format_duration(t_load.elapsed())); | ||||||
|  |         Some(ret) | ||||||
|  |     } | ||||||
|  |     fn read_record(reader: &mut BufReader<File>) -> Option<StringRecord> { | ||||||
|  |         let mut line = String::new(); | ||||||
|  |         reader.read_line(&mut line).ok()?; | ||||||
|  |         let v: Vec<_> = line.trim_end().split(',').collect(); | ||||||
|  |         let rec = StringRecord::from(v); | ||||||
|  |         Some(rec) | ||||||
|  |     } | ||||||
|  |     pub fn get(&mut self, id: u32) -> Option<System> { | ||||||
|  |         let pos = self.cache[id as usize]; | ||||||
|  |         self.file.seek(std::io::SeekFrom::Start(pos)).unwrap(); | ||||||
|  |         let rec = Self::read_record(&mut self.file).unwrap(); | ||||||
|  |         let sys: SystemSerde = rec.deserialize(self.header.as_ref()).unwrap(); | ||||||
|  |         Some(sys.build()) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub struct Router { | ||||||
|  |     tree: RTree<System>, | ||||||
|  |     scoopable: FnvHashSet<u32>, | ||||||
|  |     pub route_tree: Option<FnvHashMap<u32, u32>>, | ||||||
|  |     cache: Option<LineCache>, | ||||||
|  |     range: f32, | ||||||
|  |     primary_only: bool, | ||||||
|  |     path: PathBuf, | ||||||
|  |     callback: Box<Fn(SearchState) -> ()>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Router { | ||||||
|  |     pub fn new(path: &PathBuf, range: f32, primary_only: bool,callback: Box<Fn(SearchState) -> ()>) -> Self { | ||||||
|  |         let mut scoopable = FnvHashSet::default(); | ||||||
|  |         let mut reader = csv::ReaderBuilder::new() | ||||||
|  |             .from_path(path) | ||||||
|  |             .unwrap_or_else(|e| { | ||||||
|  |                 println!("Error opening {}: {}", path.to_str().unwrap(), e); | ||||||
|  |                 std::process::exit(1); | ||||||
|  |             }); | ||||||
|  |         let t_load = Instant::now(); | ||||||
|  |         println!("Loading {}...", path.to_str().unwrap()); | ||||||
|  |         let systems: Vec<System> = reader | ||||||
|  |             .deserialize::<SystemSerde>() | ||||||
|  |             .map(|res| res.unwrap()) | ||||||
|  |             .filter(|sys| { | ||||||
|  |                 if primary_only { | ||||||
|  |                     sys.distance == 0 | ||||||
|  |                 } else { | ||||||
|  |                     true | ||||||
|  |                 } | ||||||
|  |             }) | ||||||
|  |             .map(|sys| { | ||||||
|  |                 if sys.mult > 1.0f32 { | ||||||
|  |                     scoopable.insert(sys.id); | ||||||
|  |                 } else { | ||||||
|  |                     for c in "KGBFOAM".chars() { | ||||||
|  |                         if sys.star_type.starts_with(c) { | ||||||
|  |                             scoopable.insert(sys.id); | ||||||
|  |                             break; | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 sys.build() | ||||||
|  |             }) | ||||||
|  |             .collect(); | ||||||
|  |         println!("Building RTree..."); | ||||||
|  |         let ret = Self { | ||||||
|  |             tree: RTree::bulk_load(systems), | ||||||
|  |             scoopable, | ||||||
|  |             route_tree: None, | ||||||
|  |             range, | ||||||
|  |             primary_only, | ||||||
|  |             cache: LineCache::new(path), | ||||||
|  |             path: path.clone(), | ||||||
|  |             callback: callback, | ||||||
|  |         }; | ||||||
|  |         println!( | ||||||
|  |             "{} Systems loaded in {}", | ||||||
|  |             ret.tree.size(), | ||||||
|  |             format_duration(t_load.elapsed()) | ||||||
|  |         ); | ||||||
|  |         ret | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn from_file(filename: &PathBuf) -> (PathBuf, Self) { | ||||||
|  |         let t_load = Instant::now(); | ||||||
|  |         let mut reader = BufReader::new(File::open(&filename).unwrap()); | ||||||
|  |         println!("Loading {}", filename.to_str().unwrap()); | ||||||
|  |         let (primary, range, file_hash, path, route_tree): ( | ||||||
|  |             bool, | ||||||
|  |             f32, | ||||||
|  |             Vec<u8>, | ||||||
|  |             String, | ||||||
|  |             FnvHashMap<u32, u32>, | ||||||
|  |         ) = bincode::deserialize_from(&mut reader).unwrap(); | ||||||
|  |         let path = PathBuf::from(path); | ||||||
|  |         println!("Done in {}!", format_duration(t_load.elapsed())); | ||||||
|  |         if hash_file(&path) != file_hash { | ||||||
|  |             panic!("File hash mismatch!") | ||||||
|  |         } | ||||||
|  |         let cache = LineCache::new(&path); | ||||||
|  |         ( | ||||||
|  |             path.clone(), | ||||||
|  |             Self { | ||||||
|  |                 tree: RTree::default(), | ||||||
|  |                 scoopable: FnvHashSet::default(), | ||||||
|  |                 route_tree: Some(route_tree), | ||||||
|  |                 range, | ||||||
|  |                 cache, | ||||||
|  |                 primary_only: primary, | ||||||
|  |                 path, | ||||||
|  |                 callback: Box::new(|s| {}), | ||||||
|  |             }, | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn closest(&self, point: &[f32; 3]) -> &System { | ||||||
|  |         self.tree.nearest_neighbor(point).unwrap() | ||||||
|  |     } | ||||||
|  |     fn points_in_sphere(&self, center: &[f32; 3], radius: f32) -> impl Iterator<Item = &System> { | ||||||
|  |         self.tree.locate_within_distance(*center, radius * radius) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn neighbours(&self, sys: &System, r: f32) -> impl Iterator<Item = &System> { | ||||||
|  |         self.points_in_sphere(&sys.pos, sys.mult * r) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn valid(&self, sys: &System) -> bool { | ||||||
|  |         self.scoopable.contains(&sys.id) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn best_name_multiroute( | ||||||
|  |         &self, | ||||||
|  |         waypoints: &[String], | ||||||
|  |         range: f32, | ||||||
|  |         full: bool, | ||||||
|  |         mode: Mode, | ||||||
|  |         factor: f32, | ||||||
|  |     ) -> Vec<System> { | ||||||
|  |         let mut best_score: f32 = std::f32::MAX; | ||||||
|  |         let mut waypoints = waypoints.to_owned(); | ||||||
|  |         let mut best_permutation_waypoints = waypoints.to_owned(); | ||||||
|  |         let first = waypoints.first().cloned(); | ||||||
|  |         let last = waypoints.last().cloned(); | ||||||
|  |         let t_start = Instant::now(); | ||||||
|  |         println!("Finding best permutation of hops..."); | ||||||
|  |         while waypoints.prev_permutation() {} | ||||||
|  |         loop { | ||||||
|  |             let c_first = waypoints.first().cloned(); | ||||||
|  |             let c_last = waypoints.last().cloned(); | ||||||
|  |             if full || ((c_first == first) && (c_last == last)) { | ||||||
|  |                 let mut total_d = 0.0; | ||||||
|  |                 for pair in waypoints.windows(2) { | ||||||
|  |                     match pair { | ||||||
|  |                         [src, dst] => { | ||||||
|  |                             let (mut src, dst) = | ||||||
|  |                                 (self.name_to_systems(&src), self.name_to_systems(&dst)); | ||||||
|  |                             src.sort_by_key(|&p| (p.mult * 10.0) as u8); | ||||||
|  |                             let src = src.last().unwrap(); | ||||||
|  |                             let dst = dst.last().unwrap(); | ||||||
|  |                             total_d += src.distp2(dst); | ||||||
|  |                         } | ||||||
|  |                         _ => panic!("Invalid routing parameters!"), | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 if total_d < best_score { | ||||||
|  |                     best_score = total_d; | ||||||
|  |                     best_permutation_waypoints = waypoints.to_owned(); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             if !waypoints.next_permutation() { | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         println!("Done in {}!", format_duration(t_start.elapsed())); | ||||||
|  |         println!("Best permutation: {:?}", best_permutation_waypoints); | ||||||
|  |         self.name_multiroute(&best_permutation_waypoints, range, mode, factor) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn name_multiroute( | ||||||
|  |         &self, | ||||||
|  |         waypoints: &[String], | ||||||
|  |         range: f32, | ||||||
|  |         mode: Mode, | ||||||
|  |         factor: f32, | ||||||
|  |     ) -> Vec<System> { | ||||||
|  |         let mut coords = Vec::new(); | ||||||
|  |         for p_name in waypoints { | ||||||
|  |             let mut p_l = self.name_to_systems(p_name); | ||||||
|  |             p_l.sort_by_key(|&p| (p.mult * 10.0) as u8); | ||||||
|  |             let p = p_l.last().unwrap(); | ||||||
|  |             coords.push((p_name, p.pos)); | ||||||
|  |         } | ||||||
|  |         self.multiroute(coords.as_slice(), range, mode, factor) | ||||||
|  |     } | ||||||
|  |     pub fn multiroute( | ||||||
|  |         &self, | ||||||
|  |         waypoints: &[(&String, [f32; 3])], | ||||||
|  |         range: f32, | ||||||
|  |         mode: Mode, | ||||||
|  |         factor: f32, | ||||||
|  |     ) -> Vec<System> { | ||||||
|  |         let mut route: Vec<System> = Vec::new(); | ||||||
|  |         for pair in waypoints.windows(2) { | ||||||
|  |             match *pair { | ||||||
|  |                 [src, dst] => { | ||||||
|  |                     let block = match mode { | ||||||
|  |                         Mode::BFS => self.route_bfs(&src, &dst, range), | ||||||
|  |                         Mode::Greedy => self.route_greedy(&src, &dst, range), | ||||||
|  |                         Mode::AStar => self.route_astar(&src, &dst, range, factor), | ||||||
|  |                     }; | ||||||
|  |                     if route.is_empty() { | ||||||
|  |                         for sys in block.iter() { | ||||||
|  |                             route.push(sys.clone()); | ||||||
|  |                         } | ||||||
|  |                     } else { | ||||||
|  |                         for sys in block.iter().skip(1) { | ||||||
|  |                             route.push(sys.clone()); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 _ => panic!("Invalid routing parameters!"), | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         route | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn name_to_systems(&self, name: &str) -> Vec<&System> { | ||||||
|  |         for sys in &self.tree { | ||||||
|  |             if sys.system == name { | ||||||
|  |                 return self.neighbours(&sys, 0.0).collect(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         eprintln!("System not found: \"{}\"", name); | ||||||
|  |         std::process::exit(1); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn route_astar( | ||||||
|  |         &self, | ||||||
|  |         src: &(&String, [f32; 3]), | ||||||
|  |         dst: &(&String, [f32; 3]), | ||||||
|  |         range: f32, | ||||||
|  |         factor: f32, | ||||||
|  |     ) -> Vec<System> { | ||||||
|  |         if factor == 0.0 { | ||||||
|  |             return self.route_bfs(src, dst, range); | ||||||
|  |         } | ||||||
|  |         println!("Running A-Star with greedy factor of {}", factor); | ||||||
|  |         let (src_name, src) = src; | ||||||
|  |         let (dst_name, dst) = dst; | ||||||
|  |         let start_sys = self.closest(src); | ||||||
|  |         let goal_sys = self.closest(dst); | ||||||
|  |         { | ||||||
|  |             let d = dist(src, dst); | ||||||
|  |             println!("Plotting route from {} to {}...", src_name, dst_name); | ||||||
|  |             println!( | ||||||
|  |                 "Jump Range: {} Ly, Distance: {} Ly, Theoretical Jumps: {}", | ||||||
|  |                 range, | ||||||
|  |                 d, | ||||||
|  |                 d / range | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |         let total = self.tree.size() as f32; | ||||||
|  |         let mut prev = FnvHashMap::default(); | ||||||
|  |         let mut seen = FnvHashSet::default(); | ||||||
|  |         let t_start = Instant::now(); | ||||||
|  |         let mut found = false; | ||||||
|  |         let mut maxd = 0; | ||||||
|  |         let mut queue: Vec<(usize, usize, &System)> = Vec::new(); | ||||||
|  |         queue.push(( | ||||||
|  |             0,                                            // depth
 | ||||||
|  |             (start_sys.distp(goal_sys) / range) as usize, // h
 | ||||||
|  |             &start_sys, | ||||||
|  |         )); | ||||||
|  |         seen.insert(start_sys.id); | ||||||
|  | 
 | ||||||
|  |         while !(queue.is_empty() || found) { | ||||||
|  |             while let Some((depth, _, sys)) = queue.pop() { | ||||||
|  |                 if depth > maxd { | ||||||
|  |                     maxd = depth; | ||||||
|  |                     print!( | ||||||
|  |                         "[{}] Depth: {}, Queue: {}, Seen: {} ({:.02}%)     \r", | ||||||
|  |                         format_duration(t_start.elapsed()), | ||||||
|  |                         depth, | ||||||
|  |                         queue.len(), | ||||||
|  |                         seen.len(), | ||||||
|  |                         ((seen.len() * 100) as f32) / total | ||||||
|  |                     ); | ||||||
|  |                     std::io::stdout().flush().unwrap(); | ||||||
|  |                 } | ||||||
|  |                 if sys.id == goal_sys.id { | ||||||
|  |                     found = true; | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  |                 queue.extend( | ||||||
|  |                     self.neighbours(&sys, range) | ||||||
|  |                         .filter(|&nb| (self.valid(nb) || (nb.id == goal_sys.id))) | ||||||
|  |                         .filter(|&nb| seen.insert(nb.id)) | ||||||
|  |                         .map(|nb| { | ||||||
|  |                             prev.insert(nb.id, sys); | ||||||
|  |                             let d_g = (nb.distp(goal_sys) / range) as usize; | ||||||
|  |                             (depth + 1, d_g, nb) | ||||||
|  |                         }), | ||||||
|  |                 ); | ||||||
|  |                 queue.sort_by(|b, a| { | ||||||
|  |                     let (a_0, a_1) = (a.0 as f32, a.1 as f32); | ||||||
|  |                     let (b_0, b_1) = (b.0 as f32, b.1 as f32); | ||||||
|  |                     let v_a = a_0 + a_1 * factor; | ||||||
|  |                     let v_b = b_0 + b_1 * factor; | ||||||
|  |                     fcmp(v_a, v_b) | ||||||
|  |                 }); | ||||||
|  |                 // queue.reverse();
 | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         println!(); | ||||||
|  | 
 | ||||||
|  |         println!(); | ||||||
|  |         if !found { | ||||||
|  |             eprintln!("No route from {} to {} found!", src_name, dst_name); | ||||||
|  |             return Vec::new(); | ||||||
|  |         } | ||||||
|  |         let mut v: Vec<System> = Vec::new(); | ||||||
|  |         let mut curr_sys = goal_sys; | ||||||
|  |         loop { | ||||||
|  |             v.push(curr_sys.clone()); | ||||||
|  |             match prev.get(&curr_sys.id) { | ||||||
|  |                 Some(sys) => curr_sys = *sys, | ||||||
|  |                 None => { | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         v.reverse(); | ||||||
|  |         v | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn route_greedy( | ||||||
|  |         &self, | ||||||
|  |         src: &(&String, [f32; 3]), | ||||||
|  |         dst: &(&String, [f32; 3]), | ||||||
|  |         range: f32, | ||||||
|  |     ) -> Vec<System> { | ||||||
|  |         println!("Running Greedy-Search"); | ||||||
|  |         let (src_name, src) = src; | ||||||
|  |         let (dst_name, dst) = dst; | ||||||
|  |         let start_sys = self.closest(src); | ||||||
|  |         let goal_sys = self.closest(dst); | ||||||
|  |         { | ||||||
|  |             let d = dist(src, dst); | ||||||
|  |             println!("Plotting route from {} to {}...", src_name, dst_name); | ||||||
|  |             println!( | ||||||
|  |                 "Jump Range: {} Ly, Distance: {} Ly, Theoretical Jumps: {}", | ||||||
|  |                 range, | ||||||
|  |                 d, | ||||||
|  |                 d / range | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |         let total = self.tree.size() as f32; | ||||||
|  |         let mut prev = FnvHashMap::default(); | ||||||
|  |         let mut seen = FnvHashSet::default(); | ||||||
|  |         let t_start = Instant::now(); | ||||||
|  |         let mut found = false; | ||||||
|  |         let mut maxd = 0; | ||||||
|  |         let mut queue: Vec<(f32, f32, usize, &System)> = Vec::new(); | ||||||
|  |         queue.push((-goal_sys.mult, start_sys.distp2(goal_sys), 0, &start_sys)); | ||||||
|  |         seen.insert(start_sys.id); | ||||||
|  |         while !(queue.is_empty() || found) { | ||||||
|  |             while let Some((_, _, depth, sys)) = queue.pop() { | ||||||
|  |                 if depth > maxd { | ||||||
|  |                     maxd = depth; | ||||||
|  |                     print!( | ||||||
|  |                         "[{}] Depth: {}, Queue: {}, Seen: {} ({:.02}%)     \r", | ||||||
|  |                         format_duration(t_start.elapsed()), | ||||||
|  |                         depth, | ||||||
|  |                         queue.len(), | ||||||
|  |                         seen.len(), | ||||||
|  |                         ((seen.len() * 100) as f32) / total | ||||||
|  |                     ); | ||||||
|  |                     std::io::stdout().flush().unwrap(); | ||||||
|  |                 } | ||||||
|  |                 if sys.id == goal_sys.id { | ||||||
|  |                     found = true; | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  |                 queue.extend( | ||||||
|  |                     self.neighbours(&sys, range) | ||||||
|  |                         .filter(|&nb| (self.valid(nb) || (nb.id == goal_sys.id))) | ||||||
|  |                         .filter(|&nb| seen.insert(nb.id)) | ||||||
|  |                         .map(|nb| { | ||||||
|  |                             prev.insert(nb.id, sys); | ||||||
|  |                             (-nb.mult, nb.distp2(goal_sys), depth + 1, nb) | ||||||
|  |                         }), | ||||||
|  |                 ); | ||||||
|  |                 queue.sort_by(|a, b| fcmp(a.0, b.0).then(fcmp(a.1, b.1))); | ||||||
|  |                 queue.reverse(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         println!(); | ||||||
|  |         println!(); | ||||||
|  |         if !found { | ||||||
|  |             eprintln!("No route from {} to {} found!", src_name, dst_name); | ||||||
|  |             return Vec::new(); | ||||||
|  |         } | ||||||
|  |         let mut v: Vec<System> = Vec::new(); | ||||||
|  |         let mut curr_sys = goal_sys; | ||||||
|  |         loop { | ||||||
|  |             v.push(curr_sys.clone()); | ||||||
|  |             match prev.get(&curr_sys.id) { | ||||||
|  |                 Some(sys) => curr_sys = *sys, | ||||||
|  |                 None => { | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         v.reverse(); | ||||||
|  |         v | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn precompute(&mut self, src: &str) { | ||||||
|  |         let mut sys_l = self.name_to_systems(src); | ||||||
|  |         sys_l.sort_by_key(|&sys| (sys.mult * 10.0) as u8); | ||||||
|  |         let sys = sys_l.last().unwrap(); | ||||||
|  |         println!("Precomputing routes starting at {} ...", sys.system); | ||||||
|  |         let total = self.tree.size() as f32; | ||||||
|  |         let mut prev = FnvHashMap::default(); | ||||||
|  |         let mut seen = FnvHashSet::default(); | ||||||
|  |         let t_start = Instant::now(); | ||||||
|  |         let mut depth = 0; | ||||||
|  |         let mut queue: VecDeque<(usize, &System)> = VecDeque::new(); | ||||||
|  |         let mut queue_next: VecDeque<(usize, &System)> = VecDeque::new(); | ||||||
|  |         queue.push_front((0, &sys)); | ||||||
|  |         seen.insert(sys.id); | ||||||
|  |         while !queue.is_empty() { | ||||||
|  |             print!( | ||||||
|  |                 "[{}] Depth: {}, Queue: {}, Seen: {} ({:.02}%)     \r", | ||||||
|  |                 format_duration(t_start.elapsed()), | ||||||
|  |                 depth, | ||||||
|  |                 queue.len(), | ||||||
|  |                 seen.len(), | ||||||
|  |                 ((seen.len() * 100) as f32) / total | ||||||
|  |             ); | ||||||
|  |             std::io::stdout().flush().unwrap(); | ||||||
|  |             while let Some((d, sys)) = queue.pop_front() { | ||||||
|  |                 queue_next.extend( | ||||||
|  |                     self.neighbours(&sys, self.range) | ||||||
|  |                         // .filter(|&nb| self.valid(nb))
 | ||||||
|  |                         .filter(|&nb| seen.insert(nb.id)) | ||||||
|  |                         .map(|nb| { | ||||||
|  |                             prev.insert(nb.id, sys.id); | ||||||
|  |                             (d + 1, nb) | ||||||
|  |                         }), | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|  |             std::mem::swap(&mut queue, &mut queue_next); | ||||||
|  |             depth += 1; | ||||||
|  |         } | ||||||
|  |         self.route_tree = Some(prev); | ||||||
|  |         let ofn = format!( | ||||||
|  |             "{}_{}{}.router", | ||||||
|  |             src.replace("*", "").replace(" ", "_"), | ||||||
|  |             self.range, | ||||||
|  |             if self.primary_only { "_primary" } else { "" } | ||||||
|  |         ); | ||||||
|  |         println!("\nSaving to {}", ofn); | ||||||
|  |         let mut out_fh = BufWriter::new(File::create(&ofn).unwrap()); | ||||||
|  |         // (range, path, route_tree)
 | ||||||
|  |         let data = ( | ||||||
|  |             self.primary_only, | ||||||
|  |             self.range, | ||||||
|  |             hash_file(&self.path), | ||||||
|  |             String::from(self.path.to_str().unwrap()), | ||||||
|  |             self.route_tree.as_ref().unwrap(), | ||||||
|  |         ); | ||||||
|  |         bincode::serialize_into(&mut out_fh, &data).unwrap(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn get_systems_by_ids(&mut self, path: &PathBuf, ids: &[u32]) -> FnvHashMap<u32, System> { | ||||||
|  |         println!("Processing {}", path.to_str().unwrap()); | ||||||
|  |         let mut ret = FnvHashMap::default(); | ||||||
|  |         if let Some(c) = &mut self.cache.as_mut() { | ||||||
|  |             let mut missing = false; | ||||||
|  |             for id in ids { | ||||||
|  |                 match c.get(*id) { | ||||||
|  |                     Some(sys) => { | ||||||
|  |                         ret.insert(*id, sys); | ||||||
|  |                     } | ||||||
|  |                     None => { | ||||||
|  |                         println!("ID {} not found in cache", id); | ||||||
|  |                         missing = true; | ||||||
|  |                         break; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             if !missing { | ||||||
|  |                 return ret; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         let mut reader = csv::ReaderBuilder::new() | ||||||
|  |             .from_path(path) | ||||||
|  |             .unwrap_or_else(|e| { | ||||||
|  |                 println!("Error opening {}: {}", path.to_str().unwrap(), e); | ||||||
|  |                 std::process::exit(1); | ||||||
|  |             }); | ||||||
|  |         reader | ||||||
|  |             .deserialize::<SystemSerde>() | ||||||
|  |             .map(|res| res.unwrap()) | ||||||
|  |             .filter(|sys| ids.contains(&sys.id)) | ||||||
|  |             .map(|sys| { | ||||||
|  |                 ret.insert(sys.id, sys.build()); | ||||||
|  |             }) | ||||||
|  |             .last() | ||||||
|  |             .unwrap_or_else(|| { | ||||||
|  |                 eprintln!("Error: No systems matching {:?} found!", ids); | ||||||
|  |                 std::process::exit(1); | ||||||
|  |             }); | ||||||
|  |         ret | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn get_system_by_name(path: &PathBuf, name: &str) -> System { | ||||||
|  |         let mut reader = csv::ReaderBuilder::new() | ||||||
|  |             .from_path(path) | ||||||
|  |             .unwrap_or_else(|e| { | ||||||
|  |                 eprintln!("Error opening {}: {}", path.to_str().unwrap(), e); | ||||||
|  |                 std::process::exit(1); | ||||||
|  |             }); | ||||||
|  |         let sys = reader | ||||||
|  |             .deserialize::<SystemSerde>() | ||||||
|  |             .map(|res| res.unwrap()) | ||||||
|  |             .find(|sys| sys.system == name) | ||||||
|  |             .unwrap_or_else(|| { | ||||||
|  |                 eprintln!("Error: System '{}' not found!", name); | ||||||
|  |                 std::process::exit(1); | ||||||
|  |             }); | ||||||
|  |         sys.build() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn route_to(&mut self, dst: &str, systems_path: &PathBuf) -> Vec<System> { | ||||||
|  |         let prev = self.route_tree.as_ref().unwrap(); | ||||||
|  |         let dst = Self::get_system_by_name(&systems_path, dst); | ||||||
|  |         if !prev.contains_key(&dst.id) { | ||||||
|  |             eprintln!("System-ID {} not found", dst.id); | ||||||
|  |             std::process::exit(1); | ||||||
|  |         }; | ||||||
|  |         let mut v_ids: Vec<u32> = Vec::new(); | ||||||
|  |         let mut v: Vec<System> = Vec::new(); | ||||||
|  |         let mut curr_sys: u32 = dst.id; | ||||||
|  |         loop { | ||||||
|  |             v_ids.push(curr_sys); | ||||||
|  |             match prev.get(&curr_sys) { | ||||||
|  |                 Some(sys_id) => curr_sys = *sys_id, | ||||||
|  |                 None => { | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         v_ids.reverse(); | ||||||
|  |         let id_map = self.get_systems_by_ids(&systems_path, &v_ids); | ||||||
|  |         for sys_id in v_ids { | ||||||
|  |             let sys = id_map.get(&sys_id).unwrap(); | ||||||
|  |             v.push(sys.clone()) | ||||||
|  |         } | ||||||
|  |         v | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn route_bfs( | ||||||
|  |         &self, | ||||||
|  |         src: &(&String, [f32; 3]), | ||||||
|  |         dst: &(&String, [f32; 3]), | ||||||
|  |         range: f32, | ||||||
|  |     ) -> Vec<System> { | ||||||
|  |         println!("Running BFS"); | ||||||
|  |         let (src_name, src) = src; | ||||||
|  |         let (dst_name, dst) = dst; | ||||||
|  |         let start_sys = self.closest(src); | ||||||
|  |         let goal_sys = self.closest(dst); | ||||||
|  |         let d_total = dist(src, dst); | ||||||
|  |         { | ||||||
|  |             println!("Plotting route from {} to {}...", src_name, dst_name); | ||||||
|  |             println!( | ||||||
|  |                 "Jump Range: {} Ly, Distance: {} Ly, Estimated Jumps: {}", | ||||||
|  |                 range, | ||||||
|  |                 d_total, | ||||||
|  |                 d_total / range | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |         let total = self.tree.size() as f32; | ||||||
|  |         let mut prev = FnvHashMap::default(); | ||||||
|  |         let mut seen = FnvHashSet::default(); | ||||||
|  |         let t_start = Instant::now(); | ||||||
|  |         let mut depth = 0; | ||||||
|  |         let mut found = false; | ||||||
|  |         let mut queue: VecDeque<(usize, &System)> = VecDeque::new(); | ||||||
|  |         let mut queue_next: VecDeque<(usize, &System)> = VecDeque::new(); | ||||||
|  |         let mut d_rem = dist2(&start_sys.pos, &goal_sys.pos); | ||||||
|  |         queue.push_front((0, &start_sys)); | ||||||
|  |         seen.insert(start_sys.id); | ||||||
|  |         while !(queue.is_empty() || found) { | ||||||
|  |             print!( | ||||||
|  |                 "[{}] {:.02}% | Depth: {}, Queue: {}, Seen: {} ({:.02}%), Remaining Distance: {}    \r", | ||||||
|  |                 format_duration(t_start.elapsed()), | ||||||
|  |                 (((d_total-d_rem.sqrt())*100f32)/d_total), | ||||||
|  |                 depth, | ||||||
|  |                 queue.len(), | ||||||
|  |                 seen.len(), | ||||||
|  |                 ((seen.len() * 100) as f32) / total, | ||||||
|  |                 d_rem.sqrt() | ||||||
|  |             ); | ||||||
|  |             std::io::stdout().flush().unwrap(); | ||||||
|  |             while let Some((d, sys)) = queue.pop_front() { | ||||||
|  |                 if sys.id == goal_sys.id { | ||||||
|  |                     found = true; | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  |                 queue_next.extend( | ||||||
|  |                     self.neighbours(&sys, range) | ||||||
|  |                         .filter(|&nb| (self.valid(nb) || (nb.id == goal_sys.id))) | ||||||
|  |                         .filter(|&nb| seen.insert(nb.id)) | ||||||
|  |                         .map(|nb| { | ||||||
|  |                             prev.insert(nb.id, sys); | ||||||
|  |                             let dist = dist2(&nb.pos, &goal_sys.pos); | ||||||
|  |                             if dist < d_rem { | ||||||
|  |                                 d_rem = dist; | ||||||
|  |                             } | ||||||
|  |                             (d + 1, nb) | ||||||
|  |                         }), | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|  |             std::mem::swap(&mut queue, &mut queue_next); | ||||||
|  |             depth += 1; | ||||||
|  |         } | ||||||
|  |         println!(); | ||||||
|  |         println!(); | ||||||
|  |         if !found { | ||||||
|  |             eprintln!("No route from {} to {} found!", src_name, dst_name); | ||||||
|  |             return Vec::new(); | ||||||
|  |         } | ||||||
|  |         let mut v: Vec<System> = Vec::new(); | ||||||
|  |         let mut curr_sys = goal_sys; | ||||||
|  |         loop { | ||||||
|  |             v.push(curr_sys.clone()); | ||||||
|  |             match prev.get(&curr_sys.id) { | ||||||
|  |                 Some(sys) => curr_sys = *sys, | ||||||
|  |                 None => { | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         v.reverse(); | ||||||
|  |         v | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | pub fn route(opts: RouteOpts) -> std::io::Result<()> { | ||||||
|  |     if opts.systems.is_empty() { | ||||||
|  |         if opts.precomp_file.is_some() { | ||||||
|  |             eprintln!("Error: Please specify exatly one system"); | ||||||
|  |         } else if opts.precompute { | ||||||
|  |             eprintln!("Error: Please specify at least one system"); | ||||||
|  |         } else { | ||||||
|  |             eprintln!("Error: Please specify at least two systems"); | ||||||
|  |         } | ||||||
|  |         std::process::exit(1); | ||||||
|  |     } | ||||||
|  |     let mut path = opts.file_path; | ||||||
|  |     let mut router: Router = if opts.precomp_file.is_some() { | ||||||
|  |         let ret = Router::from_file(&opts.precomp_file.clone().unwrap()); | ||||||
|  |         path = ret.0; | ||||||
|  |         ret.1 | ||||||
|  |     } else { | ||||||
|  |         Router::new(&path, opts.range.unwrap(), opts.primary, Box::new(|state| { | ||||||
|  |             println!("State: {:?}",state); | ||||||
|  |         })) | ||||||
|  |     }; | ||||||
|  |     if opts.precompute { | ||||||
|  |         for sys in opts.systems { | ||||||
|  |             router.route_tree = None; | ||||||
|  |             router.precompute(&sys); | ||||||
|  |         } | ||||||
|  |         std::process::exit(0); | ||||||
|  |     } | ||||||
|  |     let t_route = Instant::now(); | ||||||
|  |     let route = if router.route_tree.is_some() { | ||||||
|  |         router.route_to(opts.systems.first().unwrap(), &path) | ||||||
|  |     } else if opts.permute || opts.full_permute { | ||||||
|  |         router.best_name_multiroute( | ||||||
|  |             &opts.systems, | ||||||
|  |             opts.range.unwrap(), | ||||||
|  |             opts.full_permute, | ||||||
|  |             opts.mode, | ||||||
|  |             opts.factor.unwrap_or(1.0), | ||||||
|  |         ) | ||||||
|  |     } else { | ||||||
|  |         router.name_multiroute( | ||||||
|  |             &opts.systems, | ||||||
|  |             opts.range.unwrap(), | ||||||
|  |             opts.mode, | ||||||
|  |             opts.factor.unwrap_or(1.0), | ||||||
|  |         ) | ||||||
|  |     }; | ||||||
|  |     println!("Route computed in {}\n", format_duration(t_route.elapsed())); | ||||||
|  |     if route.is_empty() { | ||||||
|  |         eprintln!("No route found!"); | ||||||
|  |         return Ok(()); | ||||||
|  |     } | ||||||
|  |     let mut total: f32 = 0.0; | ||||||
|  |     for (sys1, sys2) in route.iter().zip(route.iter().skip(1)) { | ||||||
|  |         let dist = sys1.distp(sys2); | ||||||
|  |         total += dist; | ||||||
|  |         println!( | ||||||
|  |             "{} ({}) [{}] ({},{},{}) [{} Ls]: {:.2} Ly", | ||||||
|  |             sys1.body, | ||||||
|  |             sys1.system, | ||||||
|  |             sys1.star_type, | ||||||
|  |             sys1.pos[0], | ||||||
|  |             sys1.pos[1], | ||||||
|  |             sys1.pos[2], | ||||||
|  |             sys1.distance, | ||||||
|  |             dist | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |     let sys = route.iter().last().unwrap(); | ||||||
|  |     println!( | ||||||
|  |         "{} ({}) [{}] ({},{},{}) [{} Ls]: {:.2} Ly", | ||||||
|  |         sys.body, sys.system, sys.star_type, sys.pos[0], sys.pos[1], sys.pos[2], sys.distance, 0.0 | ||||||
|  |     ); | ||||||
|  |     println!("Total: {:.2} Ly ({} Jumps)", total, route.len()); | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
							
								
								
									
										23
									
								
								setup.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								setup.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,23 @@ | ||||||
|  | from setuptools import setup | ||||||
|  | from setuptools_rust import Binding, RustExtension, Strip | ||||||
|  | 
 | ||||||
|  | setup( | ||||||
|  |     name="ed_lrr_gui", | ||||||
|  |     version="0.1.0", | ||||||
|  |     author="Daniel Seiller", | ||||||
|  |     author_email="earthnuker@gmail.com", | ||||||
|  |     url="none yet", | ||||||
|  |     rust_extensions=[ | ||||||
|  |         RustExtension( | ||||||
|  |             "_ed_lrr", | ||||||
|  |             path="rust/Cargo.toml", | ||||||
|  |             binding=Binding.PyO3, | ||||||
|  |             strip=Strip.All, | ||||||
|  |             native=True, | ||||||
|  |         ) | ||||||
|  |     ], | ||||||
|  |     packages=["ed_lrr_gui"], | ||||||
|  |     entry_points={"console_scripts": ["ed_lrr_gui=ed_lrr_gui.__main__:main"]}, | ||||||
|  |     install_requires=["PyQt5", "appdirs", "PyYAML"], | ||||||
|  |     zip_safe=False, | ||||||
|  | ) | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue