feat(GUI): Implement route plotting and fuzzy search

Implement route plotting in GUI
Use batch fuzzy search to find systems
search all systems at once after adding
added some error checking
This commit is contained in:
Daniel S. 2019-08-05 00:05:44 +02:00
parent ec3972b06c
commit c290d5eb12
18 changed files with 1075 additions and 391 deletions

40
.chglog/CHANGELOG.tpl.md Normal file
View file

@ -0,0 +1,40 @@
{{ if .Versions -}}
<a name="unreleased"></a>
## [Unreleased]
{{ if .Unreleased.CommitGroups -}}
{{ range .Unreleased.CommitGroups -}}
{{ range .Commits -}}
- {{ .Header }}
{{ end }}
{{ end -}}
{{ end -}}
{{ end -}}
{{ range .Versions }}
<a name="{{ .Tag.Name }}"></a>
## {{ if .Tag.Previous }}[{{ .Tag.Name }}]{{ else }}{{ .Tag.Name }}{{ end }} - {{ datetime "2006-01-02" .Tag.Date }}
{{ range .CommitGroups -}}
{{ range .Commits -}}
- {{ .Header }}
{{ end }}
{{ end -}}
{{- if .NoteGroups -}}
{{ range .NoteGroups -}}
### {{ .Title }}
{{ range .Notes }}
{{ .Body }}
{{ end }}
{{ end -}}
{{ end -}}
{{ end -}}
{{- if .Versions }}
[Unreleased]: {{ .Info.RepositoryURL }}/compare/{{ $latest := index .Versions 0 }}{{ $latest.Tag.Name }}...HEAD
{{ range .Versions -}}
{{ if .Tag.Previous -}}
[{{ .Tag.Name }}]: {{ $.Info.RepositoryURL }}/compare/{{ .Tag.Previous.Name }}...{{ .Tag.Name }}
{{ end -}}
{{ end -}}
{{ end -}}

13
.chglog/config.yml Normal file
View file

@ -0,0 +1,13 @@
style: gitlab
template: CHANGELOG.tpl.md
info:
title: CHANGELOG
repository_url: https://gitlab.com/Earthnuker/ed_lrr
options:
header:
pattern: "^(.*)$"
pattern_maps:
- Subject
notes:
keywords:
- BREAKING CHANGE

15
.gitignore vendored
View file

@ -1,15 +1,14 @@
/target rust/target
/dist
/build
**/*.rs.bk **/*.rs.bk
*.tmp *.tmp
*.idx *.idx
.vscode/** .vscode/**
*.csv
*.router
plot.py
*.tmp
*.idx
*.pyd *.pyd
build.bat
test.bat
__pycache__ __pycache__
DL
*.egg-info *.egg-info
pip-wheel-metadata build
rust/target/*

View file

@ -1,2 +1,3 @@
include rust/Cargo.toml include rust/Cargo.toml
include rust/.cargo/config
recursive-include rust/src * recursive-include rust/src *

11
build.bat Normal file
View file

@ -0,0 +1,11 @@
rm -rf build dist *.egg-info exe
python build_gui.py
pip uninstall -y ed_lrr_gui
pip install -I . setuptools_rust
python setup.py build
python setup.py bdist_wheel
python setup.py sdist
mkdir exe
cd exe
pyinstaller --noupx --noconsole --key="ED_LRR_GUI" --name ED_LRR_GUI ..\ed_lrr_gui\__main__.py
cd ..

View file

@ -1,2 +1,4 @@
from _ed_lrr import * from _ed_lrr import *
from . import gui from . import gui
from .router import Router
from .preprocess import Preprocessor

View file

@ -2,21 +2,28 @@ import sys
import os import os
import requests as RQ import requests as RQ
from datetime import datetime, timedelta from datetime import datetime, timedelta
from PyQt5.QtCore import QThread, pyqtSignal, Qt from PyQt5.QtCore import QTimer, QThread, pyqtSignal, Qt, QObject
from PyQt5.QtWidgets import ( from PyQt5.QtWidgets import (
QMainWindow, QMainWindow,
QApplication, QApplication,
QFileDialog, QFileDialog,
QProgressDialog, QProgressDialog,
QTreeWidgetItem, QTreeWidgetItem,
QAction,
QMessageBox,
) )
from urllib.request import Request, urlopen from urllib.request import Request, urlopen
import gzip import gzip
import pathlib
from PyQt5.QtGui import QPalette, QColor from PyQt5.QtGui import QPalette, QColor
import ed_lrr_gui import ed_lrr_gui
import ed_lrr_gui.config as cfg import ed_lrr_gui.config as cfg
from ed_lrr_gui.gui.ed_lrr import Ui_ED_LRR from ed_lrr_gui.gui.ed_lrr import Ui_ED_LRR
from ed_lrr_gui import Router, Preprocessor
import multiprocessing as MP import multiprocessing as MP
import queue
import csv
import _ed_lrr
def sizeof_fmt(num, suffix="B"): def sizeof_fmt(num, suffix="B"):
@ -37,6 +44,85 @@ class ProgressDialog(QProgressDialog):
self.setWindowModality(Qt.WindowModal) self.setWindowModality(Qt.WindowModal)
class Job(QObject):
progress = pyqtSignal("PyQt_PyObject")
def __init__(self, app, cls, *args, build_progress=None, **kwargs):
super().__init__()
self.job = cls(*args, **kwargs)
self.timer = QTimer(app)
self.app = app
self.timer.timeout.connect(self.interval)
self.timer.start(100)
self.last_val = None
self.build_progress = build_progress
self.progress_dialog = None
self.state = {}
def start(self):
"""
if self.diag_prog is None:
self.diag_prog = ProgressDialog("", "Cancel", 0, 1000, self.main_window)
if self.dl_thread:
self.diag_prog.canceled.connect(self.dl_canceled)
self.diag_prog.show()
t_elapsed = datetime.today() - self.dl_started
rate = args["done"] / t_elapsed.total_seconds()
remaining = (args["size"] - args["done"]) / rate
rate = round(rate, 2)
# print(rate, remaining)
try:
t_rem = timedelta(seconds=remaining)
except OverflowError:
t_rem = "-"
msg = "Downloading {} [{}/{}] ({}/s)\n[{}/{}]".format(
filename,
sizeof_fmt(args["done"]),
sizeof_fmt(args["size"]),
sizeof_fmt(rate),
t_round(t_elapsed),
t_round(t_rem),
)
self.diag_prog.setLabelText(msg)
self.diag_prog.setWindowTitle("Downloading EDSM Dumps")
self.diag_prog.setValue((args["done"] * 1000) // args["size"])
"""
self.started = datetime.today()
if self.build_progress:
self.progress_dialog = ProgressDialog("", "Cancel", 0, 1000, self.app)
self.progress_dialog.canceled.connect(self.cancel)
self.progress_dialog.show()
self.progress.connect(self.__build_progress)
else:
self.progress.connect(
lambda *args, **kwargs: print("PROGRESS:", *args, **kwargs)
)
return self.job.start()
def __build_progress(self, *args, **kwargs):
kwargs["self"] = self
return self.build_progress(*args, **kwargs)
def cancel(self):
self.job.terminate()
self.job = None
def done(self):
return (self.job.is_alive() == False) and (self.job.queue.empty())
def interval(self):
while True:
try:
res = self.job.queue.get(True, 0.1)
except queue.Empty:
return
if res == self.last_val:
continue
self.state.update(res)
self.progress.emit(self.state)
self.last_val = res
class DownloadThread(QThread): class DownloadThread(QThread):
progress = pyqtSignal("PyQt_PyObject") progress = pyqtSignal("PyQt_PyObject")
@ -79,45 +165,65 @@ class App(QApplication):
def __init__(self): def __init__(self):
super().__init__(sys.argv) super().__init__(sys.argv)
self.setStyle("Fusion") self.setStyle("Fusion")
self.set_pallete() self.setup_styles()
def set_pallete(self): def set_style(self, style):
colors = { print("LOAD:", style)
"Window": QColor(53, 53, 53), self.setPalette(self.styles[style])
"WindowText": Qt.white,
"Base": QColor(15, 15, 15), def setup_styles(self):
"AlternateBase": QColor(53, 53, 53), self.styles = {}
"ToolTipBase": Qt.white, styles = {
"ToolTipText": Qt.white, "Dark": {
"Text": Qt.white, "Window": QColor(53, 53, 53),
"Button": QColor(53, 53, 53), "WindowText": Qt.white,
"ButtonText": Qt.white, "Base": QColor(15, 15, 15),
"BrightText": Qt.red, "AlternateBase": QColor(53, 53, 53),
"Highlight": QColor(255, 128, 0), "ToolTipBase": Qt.white,
"HighlightedText": Qt.black, "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 style, colors in styles.items():
for entry, color in colors.items(): palette = QPalette()
palette.setColor(getattr(QPalette, entry), color) for entry, color in colors.items():
if color == Qt.darkGray: palette.setColor(getattr(QPalette, entry), color)
palette.setColor( if color == Qt.darkGray:
QPalette.Disabled, getattr(QPalette, entry), QColor(53, 53, 53) palette.setColor(
) QPalette.Disabled, getattr(QPalette, entry), QColor(53, 53, 53)
else: )
palette.setColor( else:
QPalette.Disabled, getattr(QPalette, entry), Qt.darkGray palette.setColor(
) QPalette.Disabled, getattr(QPalette, entry), Qt.darkGray
self.setPalette(palette) )
self.styles[style] = palette
self.styles["Light"] = self.style().standardPalette()
class ED_LRR(Ui_ED_LRR): class ED_LRR(Ui_ED_LRR):
dl_thread = None dl_thread = None
diag_prog = None diag_prog = None
dl_started = None dl_started = None
system_found = pyqtSignal("PyQt_PyObject")
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.config = cfg.load() self.config = cfg.load()
self.jobs = {}
def start_job(self, cls, *args, **kwargs):
print("START JOB:", cls, args, kwargs)
name = cls.__name__
if name in self.jobs and self.jobs[name].done():
del self.jobs[name]
if not name in self.jobs:
self.jobs[name] = Job(self.app, cls, *args, **kwargs)
self.jobs[name].start()
def get_open_file(self, filetypes, callback=None): def get_open_file(self, filetypes, callback=None):
fileName, _ = QFileDialog.getOpenFileName( fileName, _ = QFileDialog.getOpenFileName(
@ -148,6 +254,8 @@ class ED_LRR(Ui_ED_LRR):
self.config.history_out_path.append(path) self.config.history_out_path.append(path)
self.inp_sys_lst.addItem(path) self.inp_sys_lst.addItem(path)
self.inp_out_pp.addItem(path) self.inp_out_pp.addItem(path)
self.inp_sys_lst.setCurrentText(path)
self.inp_out_pp.setCurrentText(path)
def set_bodies_file(self, path): def set_bodies_file(self, path):
if path not in self.config.history_bodies_path: if path not in self.config.history_bodies_path:
@ -170,7 +278,7 @@ class ED_LRR(Ui_ED_LRR):
def set_comp_mode(self, _): def set_comp_mode(self, _):
if self.rd_comp.isChecked(): if self.rd_comp.isChecked():
comp_mode = "Compute Route" comp_mode = "Compute Route"
self.btn_add.setText("Search+Add") self.btn_add.setText("Add")
if self.rd_precomp.isChecked(): if self.rd_precomp.isChecked():
comp_mode = "Precompute Graph" comp_mode = "Precompute Graph"
self.btn_add.setText("Select") self.btn_add.setText("Select")
@ -178,7 +286,7 @@ class ED_LRR(Ui_ED_LRR):
self.lst_sys.setEnabled(self.rd_comp.isChecked()) self.lst_sys.setEnabled(self.rd_comp.isChecked())
self.btn_rm.setEnabled(self.rd_comp.isChecked()) self.btn_rm.setEnabled(self.rd_comp.isChecked())
self.cmb_mode.setEnabled(self.rd_comp.isChecked()) self.cmb_mode.setEnabled(self.rd_comp.isChecked())
self.btn_permute.setEnabled(self.rd_comp.isChecked()) self.chk_permute.setEnabled(self.rd_comp.isChecked())
self.lbl_keep.setEnabled(self.rd_comp.isChecked()) self.lbl_keep.setEnabled(self.rd_comp.isChecked())
self.lbl_mode.setEnabled(self.rd_comp.isChecked()) self.lbl_mode.setEnabled(self.rd_comp.isChecked())
self.chk_permute_keep_first.setEnabled(self.rd_comp.isChecked()) self.chk_permute_keep_first.setEnabled(self.rd_comp.isChecked())
@ -190,11 +298,17 @@ class ED_LRR(Ui_ED_LRR):
mode = self.cmb_mode.currentText() mode = self.cmb_mode.currentText()
self.lbl_greedyness.setEnabled(mode == "A*-Search") self.lbl_greedyness.setEnabled(mode == "A*-Search")
self.sld_greedyness.setEnabled(mode == "A*-Search") self.sld_greedyness.setEnabled(mode == "A*-Search")
self.log("ROUTE_MODE", mode)
def set_greedyness(self, value): def set_greedyness(self, value):
self.lbl_greedyness.setText("Greedyness Factor ({:.0%})".format(value / 100)) self.lbl_greedyness.setText("Greedyness Factor ({:.0%})".format(value / 100))
@property
def systems(self):
ret = []
for n in range(self.lst_sys.topLevelItemCount()):
ret.append(self.sys_to_dict(n))
return ret
def sys_to_dict(self, n): def sys_to_dict(self, n):
header = [ header = [
self.lst_sys.headerItem().data(c, 0) self.lst_sys.headerItem().data(c, 0)
@ -204,34 +318,108 @@ class ED_LRR(Ui_ED_LRR):
self.lst_sys.topLevelItem(n).data(c, 0) self.lst_sys.topLevelItem(n).data(c, 0)
for c in range(self.lst_sys.topLevelItem(n).columnCount()) for c in range(self.lst_sys.topLevelItem(n).columnCount())
] ]
return dict(zip(header, system)) ret = dict(zip(header, system))
ret["id"] = getattr(self.lst_sys.topLevelItem(n), "__id__", None)
ret.pop(None, None)
return ret
def error(self, msg):
QMessageBox.critical(self.main_window, "ERROR!", msg)
def get_sys_list(self):
if not self.inp_sys_lst.currentText():
self.error("System list is required!")
return
path = pathlib.Path(self.inp_sys_lst.currentText())
if not path.exists():
self.error("System list does not exist, run download and preprocess first!")
return
return path
def run(self): def run(self):
settings = {} if not all(s["Type"] for s in self.systems):
settings["permute"] = ( self.error('Not all systens have been resolved, please click "Search All"')
self.chk_permute_keep_first.checkState(), return
self.chk_permute_keep_last.checkState(), print(self.systems)
systems = [str(s["id"]) for s in self.systems]
jump_range = self.sb_range.value()
mode = self.cmb_mode.currentText()
primary = self.chk_primary.isChecked()
keep_first = self.chk_permute_keep_first.isChecked()
keep_last = self.chk_permute_keep_last.isChecked()
permute = self.chk_permute.isChecked()
greedyness = (
self.sld_greedyness.value() / 100
if self.sld_greedyness.isEnabled()
else None
) )
settings["range"] = self.sb_range.value() path = self.get_sys_list()
settings["systems"] = [ if path is None:
self.sys_to_dict(i) for i in range(self.lst_sys.topLevelItemCount()) return
] precomp = path.with_suffix(".idx")
print(settings) path = str(path)
progress = ProgressDialog( if not precomp.exists():
"(Not actually computing)", "Cancel", 0, 0, self.main_window precomp = None
else:
precomp = str(precomp)
mode = {
"Breadth-First Search": "bfs",
"A*-Search": "astar",
"Greedy-Search": "greedy",
}[mode]
print(
systems,
jump_range,
mode,
primary,
permute,
(keep_first, keep_last),
greedyness,
path,
precomp,
) )
progress.setWindowTitle("Computing Route") self.start_job(
progress.setFixedSize(400, 100) Router,
progress.setRange(0, 0) systems,
progress.show() jump_range,
0.1,
mode,
primary,
permute,
keep_first,
keep_last,
greedyness,
precomp,
path,
)
def find_sys_by_names(self, names):
t_s = datetime.today()
if not self.get_sys_list():
return None
ret = _ed_lrr.find_sys(names, self.inp_sys_lst.currentText())
print("Took:", datetime.today() - t_s)
return ret
def resolve_systems(self):
names = []
for n in range(self.lst_sys.topLevelItemCount()):
names.append(self.sys_to_dict(n)["Name"])
systems = self.find_sys_by_names(names)
if systems is None:
return
for i, name in enumerate(names):
_, system = systems[name]
self.lst_sys.topLevelItem(i).setData(0, 0, system["system"])
self.lst_sys.topLevelItem(i).setData(1, 0, system["star_type"])
self.lst_sys.topLevelItem(i).__id__ = system["id"]
# diff, item = self.find_sys_by_name(name)
# print("Found", (diff, item))
def add_system(self): def add_system(self):
n = self.lst_sys.topLevelItemCount() + 1
name = self.inp_sys.text() name = self.inp_sys.text()
item = QTreeWidgetItem( item = QTreeWidgetItem(self.lst_sys, [name, None])
self.lst_sys, [str(n) + ". Name: " + name, "Type: " + name[::-1]] item.resolved = False
)
item.sys_id = "SYS_ID_HERE"
item.setFlags(item.flags() & ~Qt.ItemIsDropEnabled) item.setFlags(item.flags() & ~Qt.ItemIsDropEnabled)
def remove_system(self): def remove_system(self):
@ -253,7 +441,7 @@ class ED_LRR(Ui_ED_LRR):
self.diag_prog = None self.diag_prog = None
self.dl_started = None self.dl_started = None
def handle_progress(self, args): def handle_dl_progress(self, args):
filename = os.path.split(args["outfile"])[-1] filename = os.path.split(args["outfile"])[-1]
if self.diag_prog is None: if self.diag_prog is None:
self.diag_prog = ProgressDialog("", "Cancel", 0, 1000, self.main_window) self.diag_prog = ProgressDialog("", "Cancel", 0, 1000, self.main_window)
@ -291,10 +479,15 @@ class ED_LRR(Ui_ED_LRR):
self.inp_bodies_dl.currentText(), self.inp_bodies_dl.currentText(),
self.inp_bodies_dest_dl.currentText(), self.inp_bodies_dest_dl.currentText(),
) )
self.dl_thread.progress.connect(self.handle_progress) self.dl_thread.progress.connect(self.handle_dl_progress)
self.dl_thread.start() self.dl_thread.start()
print(".") print(".")
def update_permute_chk(self, state):
self.chk_permute_keep_first.setEnabled(state)
self.chk_permute_keep_last.setEnabled(state)
self.lbl_keep.setEnabled(state)
def setup_signals(self): def setup_signals(self):
self.btn_download.clicked.connect(self.run_download) self.btn_download.clicked.connect(self.run_download)
self.inp_systems_dest_dl.setCurrentText(r"D:\devel\rust\ed_lrr_gui\DL\s.json") self.inp_systems_dest_dl.setCurrentText(r"D:\devel\rust\ed_lrr_gui\DL\s.json")
@ -307,6 +500,8 @@ class ED_LRR(Ui_ED_LRR):
self.btn_go.clicked.connect(self.run) self.btn_go.clicked.connect(self.run)
self.btn_add.clicked.connect(self.add_system) self.btn_add.clicked.connect(self.add_system)
self.btn_rm.clicked.connect(self.remove_system) self.btn_rm.clicked.connect(self.remove_system)
self.chk_permute.stateChanged.connect(self.update_permute_chk)
self.btn_search.clicked.connect(self.resolve_systems)
self.btn_out_browse_pp.clicked.connect( self.btn_out_browse_pp.clicked.connect(
lambda: self.get_save_file("CSV File (*.csv)", self.set_sys_lst) lambda: self.get_save_file("CSV File (*.csv)", self.set_sys_lst)
) )
@ -331,6 +526,14 @@ class ED_LRR(Ui_ED_LRR):
cfg.write(self.config) cfg.write(self.config)
print("BYEEEEEE!") print("BYEEEEEE!")
def setup_styles(self, win, app):
for name in app.styles:
action = QAction(app)
action.setObjectName("action_load_style_" + name)
action.setText(name)
action.triggered.connect(lambda _, name=name: app.set_style(name))
self.menuStyle.addAction(action)
def setupUi(self, MainWindow, app): def setupUi(self, MainWindow, app):
super().setupUi(MainWindow) super().setupUi(MainWindow)
self.update_dropdowns() self.update_dropdowns()
@ -339,6 +542,8 @@ class ED_LRR(Ui_ED_LRR):
self.setup_signals() self.setup_signals()
self.lst_sys.setHeaderLabels(["Name", "Type"]) self.lst_sys.setHeaderLabels(["Name", "Type"])
self.set_route_mode() self.set_route_mode()
self.update_permute_chk(self.chk_permute.isChecked())
self.setup_styles(MainWindow, app)
def main(): def main():

View file

@ -26,6 +26,14 @@ class Ui_ED_LRR(object):
ED_LRR.setDocumentMode(False) ED_LRR.setDocumentMode(False)
ED_LRR.setTabShape(QtWidgets.QTabWidget.Rounded) ED_LRR.setTabShape(QtWidgets.QTabWidget.Rounded)
self.centralwidget = QtWidgets.QWidget(ED_LRR) self.centralwidget = QtWidgets.QWidget(ED_LRR)
<<<<<<< Updated upstream
=======
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.centralwidget.sizePolicy().hasHeightForWidth())
self.centralwidget.setSizePolicy(sizePolicy)
>>>>>>> Stashed changes
self.centralwidget.setObjectName("centralwidget") self.centralwidget.setObjectName("centralwidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget) self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName("verticalLayout") self.verticalLayout.setObjectName("verticalLayout")
@ -214,9 +222,12 @@ class Ui_ED_LRR(object):
self.rd_precomp.setObjectName("rd_precomp") self.rd_precomp.setObjectName("rd_precomp")
self.gr_mode.addWidget(self.rd_precomp, 0, 2, 1, 1) self.gr_mode.addWidget(self.rd_precomp, 0, 2, 1, 1)
self.formLayout_2.setLayout(3, QtWidgets.QFormLayout.FieldRole, self.gr_mode) self.formLayout_2.setLayout(3, QtWidgets.QFormLayout.FieldRole, self.gr_mode)
<<<<<<< Updated upstream
self.btn_permute = QtWidgets.QPushButton(self.tab_route) self.btn_permute = QtWidgets.QPushButton(self.tab_route)
self.btn_permute.setObjectName("btn_permute") self.btn_permute.setObjectName("btn_permute")
self.formLayout_2.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.btn_permute) self.formLayout_2.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.btn_permute)
=======
>>>>>>> Stashed changes
self.lst_sys = QtWidgets.QTreeWidget(self.tab_route) self.lst_sys = QtWidgets.QTreeWidget(self.tab_route)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0) sizePolicy.setHorizontalStretch(0)
@ -231,6 +242,7 @@ class Ui_ED_LRR(object):
self.lst_sys.setAlternatingRowColors(True) self.lst_sys.setAlternatingRowColors(True)
self.lst_sys.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) self.lst_sys.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
self.lst_sys.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) self.lst_sys.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
<<<<<<< Updated upstream
self.lst_sys.setHeaderHidden(True) self.lst_sys.setHeaderHidden(True)
self.lst_sys.setObjectName("lst_sys") self.lst_sys.setObjectName("lst_sys")
self.lst_sys.headerItem().setText(0, "1") self.lst_sys.headerItem().setText(0, "1")
@ -241,6 +253,19 @@ class Ui_ED_LRR(object):
self.lbl_range = QtWidgets.QLabel(self.tab_route) self.lbl_range = QtWidgets.QLabel(self.tab_route)
self.lbl_range.setObjectName("lbl_range") self.lbl_range.setObjectName("lbl_range")
self.formLayout_2.setWidget(8, QtWidgets.QFormLayout.LabelRole, self.lbl_range) self.formLayout_2.setWidget(8, QtWidgets.QFormLayout.LabelRole, self.lbl_range)
=======
self.lst_sys.setHeaderHidden(False)
self.lst_sys.setObjectName("lst_sys")
self.lst_sys.headerItem().setText(0, "Name")
self.lst_sys.header().setVisible(False)
self.formLayout_2.setWidget(7, QtWidgets.QFormLayout.SpanningRole, self.lst_sys)
self.sb_range = QtWidgets.QDoubleSpinBox(self.tab_route)
self.sb_range.setObjectName("sb_range")
self.formLayout_2.setWidget(9, QtWidgets.QFormLayout.FieldRole, self.sb_range)
self.lbl_range = QtWidgets.QLabel(self.tab_route)
self.lbl_range.setObjectName("lbl_range")
self.formLayout_2.setWidget(9, QtWidgets.QFormLayout.LabelRole, self.lbl_range)
>>>>>>> Stashed changes
self.gr_opts = QtWidgets.QGridLayout() self.gr_opts = QtWidgets.QGridLayout()
self.gr_opts.setObjectName("gr_opts") self.gr_opts.setObjectName("gr_opts")
self.cmb_mode = QtWidgets.QComboBox(self.tab_route) self.cmb_mode = QtWidgets.QComboBox(self.tab_route)
@ -268,16 +293,28 @@ class Ui_ED_LRR(object):
self.lbl_mode = QtWidgets.QLabel(self.tab_route) self.lbl_mode = QtWidgets.QLabel(self.tab_route)
self.lbl_mode.setObjectName("lbl_mode") self.lbl_mode.setObjectName("lbl_mode")
self.gr_opts.addWidget(self.lbl_mode, 0, 1, 1, 1) self.gr_opts.addWidget(self.lbl_mode, 0, 1, 1, 1)
<<<<<<< Updated upstream
self.formLayout_2.setLayout(9, QtWidgets.QFormLayout.SpanningRole, self.gr_opts) self.formLayout_2.setLayout(9, QtWidgets.QFormLayout.SpanningRole, self.gr_opts)
self.btn_go = QtWidgets.QPushButton(self.tab_route) self.btn_go = QtWidgets.QPushButton(self.tab_route)
self.btn_go.setFlat(False) self.btn_go.setFlat(False)
self.btn_go.setObjectName("btn_go") self.btn_go.setObjectName("btn_go")
self.formLayout_2.setWidget(10, QtWidgets.QFormLayout.LabelRole, self.btn_go) self.formLayout_2.setWidget(10, QtWidgets.QFormLayout.LabelRole, self.btn_go)
=======
self.formLayout_2.setLayout(10, 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(11, QtWidgets.QFormLayout.LabelRole, self.btn_go)
>>>>>>> Stashed changes
self.gridLayout_4 = QtWidgets.QGridLayout() self.gridLayout_4 = QtWidgets.QGridLayout()
self.gridLayout_4.setObjectName("gridLayout_4") self.gridLayout_4.setObjectName("gridLayout_4")
self.chk_permute_keep_last = QtWidgets.QCheckBox(self.tab_route) self.chk_permute_keep_last = QtWidgets.QCheckBox(self.tab_route)
self.chk_permute_keep_last.setObjectName("chk_permute_keep_last") self.chk_permute_keep_last.setObjectName("chk_permute_keep_last")
<<<<<<< Updated upstream
self.gridLayout_4.addWidget(self.chk_permute_keep_last, 0, 2, 1, 1) self.gridLayout_4.addWidget(self.chk_permute_keep_last, 0, 2, 1, 1)
=======
self.gridLayout_4.addWidget(self.chk_permute_keep_last, 0, 3, 1, 1)
>>>>>>> Stashed changes
self.chk_permute_keep_first = QtWidgets.QCheckBox(self.tab_route) self.chk_permute_keep_first = QtWidgets.QCheckBox(self.tab_route)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0) sizePolicy.setHorizontalStretch(0)
@ -286,7 +323,11 @@ class Ui_ED_LRR(object):
self.chk_permute_keep_first.setSizePolicy(sizePolicy) self.chk_permute_keep_first.setSizePolicy(sizePolicy)
self.chk_permute_keep_first.setTristate(False) self.chk_permute_keep_first.setTristate(False)
self.chk_permute_keep_first.setObjectName("chk_permute_keep_first") self.chk_permute_keep_first.setObjectName("chk_permute_keep_first")
<<<<<<< Updated upstream
self.gridLayout_4.addWidget(self.chk_permute_keep_first, 0, 1, 1, 1) self.gridLayout_4.addWidget(self.chk_permute_keep_first, 0, 1, 1, 1)
=======
self.gridLayout_4.addWidget(self.chk_permute_keep_first, 0, 2, 1, 1)
>>>>>>> Stashed changes
self.lbl_keep = QtWidgets.QLabel(self.tab_route) self.lbl_keep = QtWidgets.QLabel(self.tab_route)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0) sizePolicy.setHorizontalStretch(0)
@ -294,8 +335,19 @@ class Ui_ED_LRR(object):
sizePolicy.setHeightForWidth(self.lbl_keep.sizePolicy().hasHeightForWidth()) sizePolicy.setHeightForWidth(self.lbl_keep.sizePolicy().hasHeightForWidth())
self.lbl_keep.setSizePolicy(sizePolicy) self.lbl_keep.setSizePolicy(sizePolicy)
self.lbl_keep.setObjectName("lbl_keep") self.lbl_keep.setObjectName("lbl_keep")
<<<<<<< Updated upstream
self.gridLayout_4.addWidget(self.lbl_keep, 0, 0, 1, 1) self.gridLayout_4.addWidget(self.lbl_keep, 0, 0, 1, 1)
self.formLayout_2.setLayout(4, QtWidgets.QFormLayout.FieldRole, self.gridLayout_4) self.formLayout_2.setLayout(4, QtWidgets.QFormLayout.FieldRole, self.gridLayout_4)
=======
self.gridLayout_4.addWidget(self.lbl_keep, 0, 1, 1, 1)
self.formLayout_2.setLayout(4, QtWidgets.QFormLayout.FieldRole, self.gridLayout_4)
self.chk_permute = QtWidgets.QCheckBox(self.tab_route)
self.chk_permute.setObjectName("chk_permute")
self.formLayout_2.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.chk_permute)
self.btn_search = QtWidgets.QPushButton(self.tab_route)
self.btn_search.setObjectName("btn_search")
self.formLayout_2.setWidget(8, QtWidgets.QFormLayout.LabelRole, self.btn_search)
>>>>>>> Stashed changes
self.tabs.addTab(self.tab_route, "") self.tabs.addTab(self.tab_route, "")
self.tab_log = QtWidgets.QWidget() self.tab_log = QtWidgets.QWidget()
self.tab_log.setObjectName("tab_log") self.tab_log.setObjectName("tab_log")
@ -317,14 +369,32 @@ class Ui_ED_LRR(object):
self.menu.setObjectName("menu") self.menu.setObjectName("menu")
self.menu_file = QtWidgets.QMenu(self.menu) self.menu_file = QtWidgets.QMenu(self.menu)
self.menu_file.setObjectName("menu_file") self.menu_file.setObjectName("menu_file")
<<<<<<< Updated upstream
=======
self.menuWindow = QtWidgets.QMenu(self.menu)
self.menuWindow.setObjectName("menuWindow")
self.menuStyle = QtWidgets.QMenu(self.menuWindow)
self.menuStyle.setObjectName("menuStyle")
>>>>>>> Stashed changes
ED_LRR.setMenuBar(self.menu) ED_LRR.setMenuBar(self.menu)
self.bar_status = QtWidgets.QStatusBar(ED_LRR) self.bar_status = QtWidgets.QStatusBar(ED_LRR)
self.bar_status.setObjectName("bar_status") self.bar_status.setObjectName("bar_status")
ED_LRR.setStatusBar(self.bar_status) ED_LRR.setStatusBar(self.bar_status)
self.menu_act_quit = QtWidgets.QAction(ED_LRR) self.menu_act_quit = QtWidgets.QAction(ED_LRR)
self.menu_act_quit.setObjectName("menu_act_quit") self.menu_act_quit.setObjectName("menu_act_quit")
<<<<<<< Updated upstream
self.menu_file.addAction(self.menu_act_quit) self.menu_file.addAction(self.menu_act_quit)
self.menu.addAction(self.menu_file.menuAction()) self.menu.addAction(self.menu_file.menuAction())
=======
self.actionA = QtWidgets.QAction(ED_LRR)
self.actionA.setObjectName("actionA")
self.actionB = QtWidgets.QAction(ED_LRR)
self.actionB.setObjectName("actionB")
self.menu_file.addAction(self.menu_act_quit)
self.menuWindow.addAction(self.menuStyle.menuAction())
self.menu.addAction(self.menu_file.menuAction())
self.menu.addAction(self.menuWindow.menuAction())
>>>>>>> Stashed changes
self.retranslateUi(ED_LRR) self.retranslateUi(ED_LRR)
self.tabs.setCurrentIndex(2) self.tabs.setCurrentIndex(2)
@ -358,12 +428,20 @@ class Ui_ED_LRR(object):
self.tabs.setTabText(self.tabs.indexOf(self.tab_preprocess), _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.lbl_sys_lst.setText(_translate("ED_LRR", "System List"))
self.btn_sys_lst_browse.setText(_translate("ED_LRR", "...")) self.btn_sys_lst_browse.setText(_translate("ED_LRR", "..."))
<<<<<<< Updated upstream
self.btn_add.setText(_translate("ED_LRR", "Search+Add")) self.btn_add.setText(_translate("ED_LRR", "Search+Add"))
=======
self.btn_add.setText(_translate("ED_LRR", "Add"))
>>>>>>> Stashed changes
self.inp_sys.setPlaceholderText(_translate("ED_LRR", "System Name")) self.inp_sys.setPlaceholderText(_translate("ED_LRR", "System Name"))
self.btn_rm.setText(_translate("ED_LRR", "Remove")) self.btn_rm.setText(_translate("ED_LRR", "Remove"))
self.rd_comp.setText(_translate("ED_LRR", "Compute Route")) self.rd_comp.setText(_translate("ED_LRR", "Compute Route"))
self.rd_precomp.setText(_translate("ED_LRR", "Precompute Graph")) self.rd_precomp.setText(_translate("ED_LRR", "Precompute Graph"))
<<<<<<< Updated upstream
self.btn_permute.setText(_translate("ED_LRR", "Permute")) self.btn_permute.setText(_translate("ED_LRR", "Permute"))
=======
self.lst_sys.headerItem().setText(1, _translate("ED_LRR", "Type"))
>>>>>>> Stashed changes
self.lbl_range.setText(_translate("ED_LRR", "Jump Range (Ly)")) self.lbl_range.setText(_translate("ED_LRR", "Jump Range (Ly)"))
self.cmb_mode.setCurrentText(_translate("ED_LRR", "Breadth-First Search")) 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(0, _translate("ED_LRR", "Breadth-First Search"))
@ -376,8 +454,22 @@ class Ui_ED_LRR(object):
self.chk_permute_keep_last.setText(_translate("ED_LRR", "Last")) self.chk_permute_keep_last.setText(_translate("ED_LRR", "Last"))
self.chk_permute_keep_first.setText(_translate("ED_LRR", "First")) self.chk_permute_keep_first.setText(_translate("ED_LRR", "First"))
self.lbl_keep.setText(_translate("ED_LRR", "Keep Endpoints:")) self.lbl_keep.setText(_translate("ED_LRR", "Keep Endpoints:"))
<<<<<<< Updated upstream
self.tabs.setTabText(self.tabs.indexOf(self.tab_route), _translate("ED_LRR", "Route")) 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.tabs.setTabText(self.tabs.indexOf(self.tab_log), _translate("ED_LRR", "Log"))
self.menu_file.setTitle(_translate("ED_LRR", "File")) self.menu_file.setTitle(_translate("ED_LRR", "File"))
self.menu_act_quit.setText(_translate("ED_LRR", "Quit")) self.menu_act_quit.setText(_translate("ED_LRR", "Quit"))
self.menu_act_quit.setShortcut(_translate("ED_LRR", "Ctrl+Q")) self.menu_act_quit.setShortcut(_translate("ED_LRR", "Ctrl+Q"))
=======
self.chk_permute.setText(_translate("ED_LRR", "Permute"))
self.btn_search.setText(_translate("ED_LRR", "Search All"))
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.menuWindow.setTitle(_translate("ED_LRR", "Window"))
self.menuStyle.setTitle(_translate("ED_LRR", "Style"))
self.menu_act_quit.setText(_translate("ED_LRR", "Quit"))
self.menu_act_quit.setShortcut(_translate("ED_LRR", "Ctrl+Q"))
self.actionA.setText(_translate("ED_LRR", "A"))
self.actionB.setText(_translate("ED_LRR", "B"))
>>>>>>> Stashed changes

View file

@ -44,6 +44,15 @@
<enum>QTabWidget::Rounded</enum> <enum>QTabWidget::Rounded</enum>
</property> </property>
<widget class="QWidget" name="centralwidget"> <widget class="QWidget" name="centralwidget">
<<<<<<< Updated upstream
=======
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
>>>>>>> Stashed changes
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<item> <item>
<widget class="QTabWidget" name="tabs"> <widget class="QTabWidget" name="tabs">
@ -363,7 +372,11 @@
<item row="1" column="0"> <item row="1" column="0">
<widget class="QPushButton" name="btn_add"> <widget class="QPushButton" name="btn_add">
<property name="text"> <property name="text">
<<<<<<< Updated upstream
<string>Search+Add</string> <string>Search+Add</string>
=======
<string>Add</string>
>>>>>>> Stashed changes
</property> </property>
</widget> </widget>
</item> </item>
@ -402,6 +415,7 @@
</item> </item>
</layout> </layout>
</item> </item>
<<<<<<< Updated upstream
<item row="4" column="0"> <item row="4" column="0">
<widget class="QPushButton" name="btn_permute"> <widget class="QPushButton" name="btn_permute">
<property name="text"> <property name="text">
@ -409,6 +423,8 @@
</property> </property>
</widget> </widget>
</item> </item>
=======
>>>>>>> Stashed changes
<item row="7" column="0" colspan="2"> <item row="7" column="0" colspan="2">
<widget class="QTreeWidget" name="lst_sys"> <widget class="QTreeWidget" name="lst_sys">
<property name="sizePolicy"> <property name="sizePolicy">
@ -445,26 +461,53 @@
<enum>QAbstractItemView::SelectRows</enum> <enum>QAbstractItemView::SelectRows</enum>
</property> </property>
<property name="headerHidden"> <property name="headerHidden">
<<<<<<< Updated upstream
<bool>true</bool> <bool>true</bool>
</property> </property>
<column> <column>
<property name="text"> <property name="text">
<string notr="true">1</string> <string notr="true">1</string>
=======
<bool>false</bool>
</property>
<attribute name="headerVisible">
<bool>false</bool>
</attribute>
<column>
<property name="text">
<string notr="true">Name</string>
</property>
</column>
<column>
<property name="text">
<string>Type</string>
>>>>>>> Stashed changes
</property> </property>
</column> </column>
</widget> </widget>
</item> </item>
<<<<<<< Updated upstream
<item row="8" column="1"> <item row="8" column="1">
<widget class="QDoubleSpinBox" name="sb_range"/> <widget class="QDoubleSpinBox" name="sb_range"/>
</item> </item>
<item row="8" column="0"> <item row="8" column="0">
=======
<item row="9" column="1">
<widget class="QDoubleSpinBox" name="sb_range"/>
</item>
<item row="9" column="0">
>>>>>>> Stashed changes
<widget class="QLabel" name="lbl_range"> <widget class="QLabel" name="lbl_range">
<property name="text"> <property name="text">
<string>Jump Range (Ly)</string> <string>Jump Range (Ly)</string>
</property> </property>
</widget> </widget>
</item> </item>
<<<<<<< Updated upstream
<item row="9" column="0" colspan="2"> <item row="9" column="0" colspan="2">
=======
<item row="10" column="0" colspan="2">
>>>>>>> Stashed changes
<layout class="QGridLayout" name="gr_opts"> <layout class="QGridLayout" name="gr_opts">
<item row="0" column="2"> <item row="0" column="2">
<widget class="QComboBox" name="cmb_mode"> <widget class="QComboBox" name="cmb_mode">
@ -536,7 +579,11 @@
</item> </item>
</layout> </layout>
</item> </item>
<<<<<<< Updated upstream
<item row="10" column="0"> <item row="10" column="0">
=======
<item row="11" column="0">
>>>>>>> Stashed changes
<widget class="QPushButton" name="btn_go"> <widget class="QPushButton" name="btn_go">
<property name="text"> <property name="text">
<string>GO!</string> <string>GO!</string>
@ -548,14 +595,22 @@
</item> </item>
<item row="4" column="1"> <item row="4" column="1">
<layout class="QGridLayout" name="gridLayout_4"> <layout class="QGridLayout" name="gridLayout_4">
<<<<<<< Updated upstream
<item row="0" column="2"> <item row="0" column="2">
=======
<item row="0" column="3">
>>>>>>> Stashed changes
<widget class="QCheckBox" name="chk_permute_keep_last"> <widget class="QCheckBox" name="chk_permute_keep_last">
<property name="text"> <property name="text">
<string>Last</string> <string>Last</string>
</property> </property>
</widget> </widget>
</item> </item>
<<<<<<< Updated upstream
<item row="0" column="1"> <item row="0" column="1">
=======
<item row="0" column="2">
>>>>>>> Stashed changes
<widget class="QCheckBox" name="chk_permute_keep_first"> <widget class="QCheckBox" name="chk_permute_keep_first">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed"> <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
@ -571,7 +626,11 @@
</property> </property>
</widget> </widget>
</item> </item>
<<<<<<< Updated upstream
<item row="0" column="0"> <item row="0" column="0">
=======
<item row="0" column="1">
>>>>>>> Stashed changes
<widget class="QLabel" name="lbl_keep"> <widget class="QLabel" name="lbl_keep">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
@ -586,6 +645,23 @@
</item> </item>
</layout> </layout>
</item> </item>
<<<<<<< Updated upstream
=======
<item row="4" column="0">
<widget class="QCheckBox" name="chk_permute">
<property name="text">
<string>Permute</string>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QPushButton" name="btn_search">
<property name="text">
<string>Search All</string>
</property>
</widget>
</item>
>>>>>>> Stashed changes
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="tab_log"> <widget class="QWidget" name="tab_log">
@ -633,7 +709,23 @@
</property> </property>
<addaction name="menu_act_quit"/> <addaction name="menu_act_quit"/>
</widget> </widget>
<<<<<<< Updated upstream
<addaction name="menu_file"/> <addaction name="menu_file"/>
=======
<widget class="QMenu" name="menuWindow">
<property name="title">
<string>Window</string>
</property>
<widget class="QMenu" name="menuStyle">
<property name="title">
<string>Style</string>
</property>
</widget>
<addaction name="menuStyle"/>
</widget>
<addaction name="menu_file"/>
<addaction name="menuWindow"/>
>>>>>>> Stashed changes
</widget> </widget>
<widget class="QStatusBar" name="bar_status"/> <widget class="QStatusBar" name="bar_status"/>
<action name="menu_act_quit"> <action name="menu_act_quit">
@ -644,6 +736,19 @@
<string>Ctrl+Q</string> <string>Ctrl+Q</string>
</property> </property>
</action> </action>
<<<<<<< Updated upstream
=======
<action name="actionA">
<property name="text">
<string>A</string>
</property>
</action>
<action name="actionB">
<property name="text">
<string>B</string>
</property>
</action>
>>>>>>> Stashed changes
</widget> </widget>
<tabstops> <tabstops>
<tabstop>rd_comp</tabstop> <tabstop>rd_comp</tabstop>

View file

@ -14,24 +14,13 @@ class Preprocessor(Process):
self.args = args self.args = args
self.kwargs = kwargs self.kwargs = kwargs
self.kwargs["callback"] = self.callback self.kwargs["callback"] = self.callback
self.start()
def __iter__(self):
while self.is_alive():
try:
self.state.update(self.queue.get(True, 0.5))
yield self.state
except queue.Empty:
pass
while not self.queue.empty():
self.state.update(self.queue.get(True, 0.5))
yield self.state
def callback(self, state): def callback(self, state):
self.queue.put({"status": state}) self.queue.put({"status": state})
def run(self): def run(self):
_ed_lrr.preprocess(*self.args, **self.kwargs) res = _ed_lrr.preprocess(*self.args, **self.kwargs)
self.queue.put({"result": res})
if __name__ == "__main__": if __name__ == "__main__":

View file

@ -14,18 +14,6 @@ class Router(Process):
self.args = args self.args = args
self.kwargs = kwargs self.kwargs = kwargs
self.kwargs["callback"] = self.callback self.kwargs["callback"] = self.callback
self.start()
def __iter__(self):
while self.is_alive():
try:
self.state.update(self.queue.get(True, 0.5))
yield self.state
except queue.Empty:
pass
while not self.queue.empty():
self.state.update(self.queue.get(True, 0.5))
yield self.state
def callback(self, state): def callback(self, state):
self.queue.put({"status": state}) self.queue.put({"status": state})

88
rust/Cargo.lock generated
View file

@ -168,10 +168,19 @@ dependencies = [
"indicatif 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "indicatif 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"permutohedron 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "permutohedron 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"pyo3 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "pyo3 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
<<<<<<< Updated upstream:rust/Cargo.lock
"rstar 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rstar 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
=======
"rstar 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
"sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
"strsim 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
"structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
>>>>>>> Stashed changes:Cargo.lock
] ]
[[package]] [[package]]
@ -205,6 +214,19 @@ dependencies = [
[[package]] [[package]]
name = "ghost" name = "ghost"
version = "0.1.0" version = "0.1.0"
<<<<<<< Updated upstream:rust/Cargo.lock
=======
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "heck"
version = "0.3.1"
>>>>>>> Stashed changes:Cargo.lock
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
@ -294,7 +316,11 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"mashup-impl 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "mashup-impl 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
<<<<<<< Updated upstream:rust/Cargo.lock
"proc-macro-hack 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro-hack 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
=======
"proc-macro-hack 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
>>>>>>> Stashed changes:Cargo.lock
] ]
[[package]] [[package]]
@ -302,7 +328,11 @@ name = "mashup-impl"
version = "0.1.9" version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
<<<<<<< Updated upstream:rust/Cargo.lock
"proc-macro-hack 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro-hack 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
=======
"proc-macro-hack 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
>>>>>>> Stashed changes:Cargo.lock
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -377,15 +407,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "proc-macro-hack" name = "proc-macro-hack"
<<<<<<< Updated upstream:rust/Cargo.lock
version = "0.4.1" version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"proc-macro-hack-impl 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro-hack-impl 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
=======
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro-hack-impl 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
>>>>>>> Stashed changes:Cargo.lock
] ]
[[package]] [[package]]
name = "proc-macro-hack-impl" name = "proc-macro-hack-impl"
<<<<<<< Updated upstream:rust/Cargo.lock
version = "0.4.1" version = "0.4.1"
=======
version = "0.4.2"
>>>>>>> Stashed changes:Cargo.lock
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
@ -592,7 +633,7 @@ dependencies = [
[[package]] [[package]]
name = "rstar" name = "rstar"
version = "0.4.0" version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -679,6 +720,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "spin" name = "spin"
version = "0.5.0" version = "0.5.0"
<<<<<<< Updated upstream:rust/Cargo.lock
=======
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "strsim"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "strsim"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "structopt"
version = "0.2.18"
>>>>>>> Stashed changes:Cargo.lock
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
@ -748,6 +807,11 @@ name = "version_check"
version = "0.1.5" version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "version_check"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "winapi" name = "winapi"
version = "0.3.7" version = "0.3.7"
@ -792,6 +856,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
"checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" "checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"
"checksum ghost 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5297b71943dc9fea26a3241b178c140ee215798b7f79f7773fd61683e25bca74" "checksum ghost 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5297b71943dc9fea26a3241b178c140ee215798b7f79f7773fd61683e25bca74"
<<<<<<< Updated upstream:rust/Cargo.lock
=======
"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
>>>>>>> Stashed changes:Cargo.lock
"checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" "checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114"
"checksum indicatif 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2c60da1c9abea75996b70a931bba6c750730399005b61ccd853cee50ef3d0d0c" "checksum indicatif 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2c60da1c9abea75996b70a931bba6c750730399005b61ccd853cee50ef3d0d0c"
"checksum inventory 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "21df85981fe094480bc2267723d3dc0fd1ae0d1f136affc659b7398be615d922" "checksum inventory 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "21df85981fe094480bc2267723d3dc0fd1ae0d1f136affc659b7398be615d922"
@ -813,8 +881,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum parking_lot_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb88cb1cb3790baa6776844f968fea3be44956cf184fa1be5a03341f5491278c" "checksum parking_lot_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb88cb1cb3790baa6776844f968fea3be44956cf184fa1be5a03341f5491278c"
"checksum pdqselect 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ec91767ecc0a0bbe558ce8c9da33c068066c57ecc8bb8477ef8c1ad3ef77c27" "checksum pdqselect 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ec91767ecc0a0bbe558ce8c9da33c068066c57ecc8bb8477ef8c1ad3ef77c27"
"checksum permutohedron 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b687ff7b5da449d39e418ad391e5e08da53ec334903ddbb921db208908fc372c" "checksum permutohedron 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b687ff7b5da449d39e418ad391e5e08da53ec334903ddbb921db208908fc372c"
<<<<<<< Updated upstream:rust/Cargo.lock
"checksum proc-macro-hack 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c725b36c99df7af7bf9324e9c999b9e37d92c8f8caf106d82e1d7953218d2d8" "checksum proc-macro-hack 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c725b36c99df7af7bf9324e9c999b9e37d92c8f8caf106d82e1d7953218d2d8"
"checksum proc-macro-hack-impl 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2b753ad9ed99dd8efeaa7d2fb8453c8f6bc3e54b97966d35f1bc77ca6865254a" "checksum proc-macro-hack-impl 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2b753ad9ed99dd8efeaa7d2fb8453c8f6bc3e54b97966d35f1bc77ca6865254a"
=======
"checksum proc-macro-hack 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "463bf29e7f11344e58c9e01f171470ab15c925c6822ad75028cc1c0e1d1eb63b"
"checksum proc-macro-hack-impl 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "38c47dcb1594802de8c02f3b899e2018c78291168a22c281be21ea0fb4796842"
>>>>>>> Stashed changes:Cargo.lock
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
"checksum pyo3 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d09e6e2d3fa5ae1a8af694f865e03e763e730768b16e3097851ff0b7f2276086" "checksum pyo3 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d09e6e2d3fa5ae1a8af694f865e03e763e730768b16e3097851ff0b7f2276086"
"checksum pyo3-derive-backend 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9d7ae8ab3017515cd7c82d88ce49b55e12a56c602dc69993e123da45c91b186" "checksum pyo3-derive-backend 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9d7ae8ab3017515cd7c82d88ce49b55e12a56c602dc69993e123da45c91b186"
@ -837,7 +910,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0b2f0808e7d7e4fb1cb07feb6ff2f4bc827938f24f8c2e6a3beb7370af544bdd" "checksum regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0b2f0808e7d7e4fb1cb07feb6ff2f4bc827938f24f8c2e6a3beb7370af544bdd"
"checksum regex-automata 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3ed09217220c272b29ef237a974ad58515bde75f194e3ffa7e6d0bf0f3b01f86" "checksum regex-automata 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3ed09217220c272b29ef237a974ad58515bde75f194e3ffa7e6d0bf0f3b01f86"
"checksum regex-syntax 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d76410686f9e3a17f06128962e0ecc5755870bb890c34820c7af7f1db2e1d48" "checksum regex-syntax 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d76410686f9e3a17f06128962e0ecc5755870bb890c34820c7af7f1db2e1d48"
"checksum rstar 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dd08ae4f9661517777346592956ea6cdbba2895a28037af7daa600382f4b4001" "checksum rstar 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e90bb34cd8efef7ed3ebfb29e713e51301c3e60fba37c3e9185a1afaf9ce643a"
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" "checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997"
"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" "checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d"
@ -849,6 +922,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd26bc0e7a2e3a7c959bc494caf58b72ee0c71d67704e9520f736ca7e4853ecf" "checksum sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd26bc0e7a2e3a7c959bc494caf58b72ee0c71d67704e9520f736ca7e4853ecf"
"checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7" "checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7"
"checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55" "checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55"
<<<<<<< Updated upstream:rust/Cargo.lock
=======
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
"checksum strsim 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "032c03039aae92b350aad2e3779c352e104d919cb192ba2fabbd7b831ce4f0f6"
"checksum structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "16c2cdbf9cc375f15d1b4141bc48aeef444806655cd0e904207edc8d68d86ed7"
"checksum structopt-derive 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "53010261a84b37689f9ed7d395165029f9cc7abb9f56bbfe86bee2597ed25107"
>>>>>>> Stashed changes:Cargo.lock
"checksum syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d960b829a55e56db167e861ddb43602c003c7be0bee1d345021703fac2fb7c" "checksum syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d960b829a55e56db167e861ddb43602c003c7be0bee1d345021703fac2fb7c"
"checksum termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a8fb22f7cde82c8220e5aeacb3258ed7ce996142c77cba193f203515e26c330" "checksum termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a8fb22f7cde82c8220e5aeacb3258ed7ce996142c77cba193f203515e26c330"
"checksum termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72b620c5ea021d75a735c943269bb07d30c9b77d6ac6b236bc8b5c496ef05625" "checksum termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72b620c5ea021d75a735c943269bb07d30c9b77d6ac6b236bc8b5c496ef05625"
@ -858,6 +938,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
"checksum utf8-ranges 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9d50aa7650df78abf942826607c62468ce18d9019673d4a2ebe1865dbb96ffde" "checksum utf8-ranges 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9d50aa7650df78abf942826607c62468ce18d9019673d4a2ebe1865dbb96ffde"
<<<<<<< Updated upstream:rust/Cargo.lock
=======
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
>>>>>>> Stashed changes:Cargo.lock
"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" "checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"

View file

@ -11,12 +11,12 @@ license = "WTFPL"
crate-type = ["cdylib"] crate-type = ["cdylib"]
[profile.release] [profile.release]
debug=true #debug=true
[dependencies] [dependencies]
csv = "1.1.1" csv = "1.1.1"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
rstar = "0.4.0" rstar = "0.5.0"
humantime = "1.2.0" humantime = "1.2.0"
permutohedron = "0.2.4" permutohedron = "0.2.4"
serde_json = "1.0.40" serde_json = "1.0.40"
@ -25,6 +25,7 @@ fnv = "1.0.6"
bincode = "1.1.4" bincode = "1.1.4"
sha3 = "0.8.2" sha3 = "0.8.2"
byteorder = "1.3.2" byteorder = "1.3.2"
strsim = "0.9.2"
[dependencies.pyo3] [dependencies.pyo3]
version = "0.7.0" version = "0.7.0"

View file

@ -27,6 +27,7 @@ impl SystemSerde {
} }
} }
#[derive(Debug, Clone, Deserialize, Serialize)] #[derive(Debug, Clone, Deserialize, Serialize)]
pub struct System { pub struct System {
pub id: u32, pub id: u32,
@ -37,3 +38,16 @@ pub struct System {
pub distance: u32, pub distance: u32,
pub pos: [f32; 3], pub pos: [f32; 3],
} }
impl Ord for System {
fn cmp(&self, other: &Self) -> Ordering {
return self.id.cmp(&other.id);
}
}
impl PartialOrd for System {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
return Some(self.cmp(other));
}
}

View file

@ -1,14 +1,43 @@
extern crate strsim;
mod common; mod common;
mod preprocess; mod preprocess;
mod route; mod route;
use pyo3::prelude::*; use std::collections::HashMap;
use pyo3::types::{PyDict,PyList};
use pyo3::exceptions::*; use pyo3::exceptions::*;
use pyo3::prelude::*;
use pyo3::types::{PyDict, PyList};
use std::path::PathBuf; use std::path::PathBuf;
use common::{System,SystemSerde};
fn find_matches(path:&PathBuf,names:Vec<String>) -> Result<HashMap<String,(f64,Option<System>)>,String> {
let mut best: HashMap<String,(f64,Option<System>)> = HashMap::new();
for name in &names {
best.insert(name.to_string(),(0.0,None));
};
let mut reader = match csv::ReaderBuilder::new().from_path(path) {
Ok(rdr) => rdr,
Err(e) => {
return Err(format!("Error opening {}: {}", path.to_str().unwrap(), e).to_string());
}
};
let systems=reader
.deserialize::<SystemSerde>();
for sys in systems {
let sys=sys.unwrap();
for name in &names {
best.entry(name.clone()).and_modify(|ent| {
let d1=strsim::normalized_levenshtein(&sys.system,&name);
if d1>ent.0 {
*ent=(d1,Some(sys.build()))
}
});
}
}
return Ok(best);
}
#[pymodule] #[pymodule]
pub fn _ed_lrr(_py: Python, m: &PyModule) -> PyResult<()> { pub fn _ed_lrr(_py: Python, m: &PyModule) -> PyResult<()> {
/// preprocess(infile_systems, infile_bodies, outfile, callback) /// preprocess(infile_systems, infile_bodies, outfile, callback)
/// -- /// --
/// ///
@ -24,108 +53,139 @@ pub fn _ed_lrr(_py: Python, m: &PyModule) -> PyResult<()> {
use preprocess::*; use preprocess::*;
let state = PyDict::new(py); let state = PyDict::new(py);
let state_dict = PyDict::new(py); let state_dict = PyDict::new(py);
callback.call(py,(state_dict,),None).unwrap(); callback.call(py, (state_dict,), None).unwrap();
let callback_wrapped = move |state: &PreprocessState| { let callback_wrapped = move |state: &PreprocessState| {
// println!("SEND: {:?}",state); // println!("SEND: {:?}",state);
state_dict.set_item("file",state.file.clone())?; state_dict.set_item("file", state.file.clone())?;
state_dict.set_item("total",state.total)?; state_dict.set_item("total", state.total)?;
state_dict.set_item("done",state.done)?; state_dict.set_item("count", state.count)?;
callback.call(py,(state_dict,),None) state_dict.set_item("done", state.done)?;
state_dict.set_item("message", state.message.clone())?;
callback.call(py, (state_dict,), None)
}; };
preprocess_files(&PathBuf::from(infile_bodies), &PathBuf::from(infile_systems), &PathBuf::from(outfile), Box::new(callback_wrapped)).unwrap(); preprocess_files(
return Ok(state.to_object(py)); &PathBuf::from(infile_bodies),
&PathBuf::from(infile_systems),
&PathBuf::from(outfile),
Box::new(callback_wrapped),
)
.unwrap();
Ok(state.to_object(py))
} }
/// route(infile, hops, range, mode,primary, greedyness, precomp, callback) ///find_sys(sys_names,sys_list)
/// --
///
/// Find system by name
#[pyfn(m, "find_sys")]
fn find_sys(py:Python,sys_names:Vec<String>,sys_list:String) -> PyResult<PyObject> {
let path=PathBuf::from(sys_list);
match find_matches(&path,sys_names) {
Ok(vals) => {
let ret=PyDict::new(py);
for (key,(diff,sys)) in vals {
let ret_dict=PyDict::new(py);
if let Some(val)= sys {
let pos = PyList::new(py, val.pos.iter());
ret_dict.set_item("star_type", val.star_type.clone())?;
ret_dict.set_item("system", val.system.clone())?;
ret_dict.set_item("body", val.body.clone())?;
ret_dict.set_item("distance", val.distance)?;
ret_dict.set_item("pos", pos)?;
ret_dict.set_item("id", val.id)?;
ret.set_item(key,(diff,ret_dict).to_object(py))?;
}
}
return Ok(ret.to_object(py));
},
Err(e) => {
return Err(PyErr::new::<ValueError, _>(e));
}
}
}
/// route(infile, hops, range, radius_mult, mode,primary, greedyness, precomp, callback)
/// -- /// --
/// ///
/// Compute a Route using the suplied parameters /// Compute a Route using the suplied parameters
#[pyfn(m, "route")] #[pyfn(m, "route")]
#[allow(clippy::too_many_arguments)]
fn route( fn route(
py: Python<'static>, py: Python<'static>,
hops: Vec<String>, hops: Vec<String>,
range: f32, range: f32,
radius_mult: f32,
mode: String, mode: String,
primary: bool, primary: bool,
permute: bool, permute: bool,
keep_first: bool,
keep_last: bool,
greedyness: Option<f32>, greedyness: Option<f32>,
precomp: Option<String>, precomp: Option<String>,
path: String, path: String,
callback: PyObject, callback: PyObject,
) -> PyResult<PyObject> { ) -> PyResult<PyObject> {
use route::*; use route::*;
// TODO: Verify Parameters
let mode = match Mode::parse(&mode) { let mode = match Mode::parse(&mode) {
Ok(val) => val, Ok(val) => val,
Err(e) => { Err(e) => {
return Err(PyErr::new::<ValueError,_>(e)); return Err(PyErr::new::<ValueError, _>(e));
} }
}; };
let state_dict = PyDict::new(py); let state_dict = PyDict::new(py);
callback.call(py,(state_dict,),None).unwrap(); callback.call(py, (state_dict,), None).unwrap();
let callback_wrapped = move |state: &SearchState| { let callback_wrapped = move |state: &SearchState| {
println!("SEND: {:?}",state); state_dict.set_item("mode", state.mode.clone())?;
state_dict.set_item("mode",state.mode.clone())?; state_dict.set_item("system", state.system.clone())?;
state_dict.set_item("system",state.system.clone())?; state_dict.set_item("body", state.body.clone())?;
state_dict.set_item("body",state.body.clone())?; state_dict.set_item("depth", state.depth)?;
state_dict.set_item("depth",state.depth)?; state_dict.set_item("queue_size", state.queue_size)?;
state_dict.set_item("queue_size",state.queue_size)?; state_dict.set_item("d_rem", state.d_rem)?;
state_dict.set_item("d_rem",state.d_rem)?; state_dict.set_item("d_total", state.d_total)?;
state_dict.set_item("d_total",state.d_total)?; state_dict.set_item("prc_done", state.prc_done)?;
state_dict.set_item("prc_done",state.prc_done)?; state_dict.set_item("n_seen", state.n_seen)?;
state_dict.set_item("n_seen",state.n_seen)?; state_dict.set_item("prc_seen", state.prc_seen)?;
state_dict.set_item("prc_seen",state.prc_seen)?; callback.call(py, (state_dict,), None)
callback.call(py,(state_dict,),None)
}; };
let opts=RouteOpts{ let mut systems=Vec::new();
systems:hops, for sys in hops {
range:Some(range), systems.push(route::SysEntry::parse(&sys))
}
println!("SYSTEMS: {:?}",systems);
let opts = RouteOpts {
systems,
range: Some(range),
file_path: PathBuf::from(path), file_path: PathBuf::from(path),
precomp_file: precomp.map(PathBuf::from), precomp_file: precomp.map(PathBuf::from),
callback: Box::new(callback_wrapped), callback: Box::new(callback_wrapped),
mode, mode,
factor: greedyness, factor: greedyness,
precompute: false, precompute: false,
permute: permute, permute,
keep_first: true, keep_first,
keep_last: true, keep_last,
primary primary,
radius_mult
}; };
let none=().to_object(py); let none = ().to_object(py);
match route(opts) { match route(opts) {
Ok(Some(route)) => { Ok(Some(route)) => {
let hops=route.iter().map(|hop| { let hops = route.iter().map(|hop| {
let pos=PyList::new(py,hop.pos.iter()); let pos = PyList::new(py, hop.pos.iter());
let elem=PyDict::new(py); let elem = PyDict::new(py);
elem.set_item("star_type",hop.star_type.clone()).unwrap(); elem.set_item("star_type", hop.star_type.clone()).unwrap();
elem.set_item("system",hop.system.clone()).unwrap(); elem.set_item("system", hop.system.clone()).unwrap();
elem.set_item("body",hop.body.clone()).unwrap(); elem.set_item("body", hop.body.clone()).unwrap();
elem.set_item("distance",hop.distance).unwrap(); elem.set_item("distance", hop.distance).unwrap();
elem.set_item("pos",pos).unwrap(); elem.set_item("pos", pos).unwrap();
return elem; elem
}); });
let lst=PyList::new(py,hops); let lst = PyList::new(py, hops);
return Ok(lst.to_object(py)); Ok(lst.to_object(py))
} }
Ok(None) => { Ok(None) => Ok(none),
return Ok(none); Err(e) => Err(PyErr::new::<ValueError, _>(e)),
}, }
Err(e) => {
return Err(PyErr::new::<ValueError,_>(e));
}
};
/*
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 callback.call(py,(state.to_object(py),),None);
*/
} }
Ok(()) Ok(())
} }

View file

@ -1,8 +1,10 @@
use crate::common::{System, SystemSerde};
use core::cmp::Ordering; use core::cmp::Ordering;
use csv::StringRecord; use csv::StringRecord;
use fnv::{FnvHashMap, FnvHashSet}; use fnv::{FnvHashMap, FnvHashSet};
use humantime::format_duration; use humantime::format_duration;
use permutohedron::LexicalPermutation; use permutohedron::LexicalPermutation;
use pyo3::prelude::*;
use rstar::{PointDistance, RTree, RTreeObject, AABB}; use rstar::{PointDistance, RTree, RTreeObject, AABB};
use sha3::{Digest, Sha3_256}; use sha3::{Digest, Sha3_256};
use std::collections::VecDeque; use std::collections::VecDeque;
@ -12,8 +14,6 @@ use std::io::Seek;
use std::io::{BufRead, BufReader, BufWriter, Write}; use std::io::{BufRead, BufReader, BufWriter, Write};
use std::path::PathBuf; use std::path::PathBuf;
use std::time::Instant; use std::time::Instant;
use pyo3::prelude::*;
use crate::common::{System, SystemSerde};
#[derive(Debug)] #[derive(Debug)]
pub struct SearchState { pub struct SearchState {
@ -26,9 +26,23 @@ pub struct SearchState {
pub d_total: f32, pub d_total: f32,
pub prc_done: f32, pub prc_done: f32,
pub n_seen: usize, pub n_seen: usize,
pub prc_seen: f32 pub prc_seen: f32,
} }
#[derive(Debug, Clone)]
pub enum SysEntry {
ID(u32),
Name(String),
}
impl SysEntry {
pub fn parse(s: &str) -> SysEntry {
match s.parse() {
Ok(n) => SysEntry::ID(n),
_ => SysEntry::Name(s.to_owned()),
}
}
}
pub struct RouteOpts { pub struct RouteOpts {
pub range: Option<f32>, pub range: Option<f32>,
@ -41,8 +55,9 @@ pub struct RouteOpts {
pub keep_last: bool, pub keep_last: bool,
pub factor: Option<f32>, pub factor: Option<f32>,
pub mode: Mode, pub mode: Mode,
pub systems: Vec<String>, pub radius_mult: f32,
pub callback: Box<dyn Fn(&SearchState) -> PyResult<PyObject>> pub systems: Vec<SysEntry>,
pub callback: Box<dyn Fn(&SearchState) -> PyResult<PyObject>>,
} }
#[derive(Debug)] #[derive(Debug)]
@ -52,9 +67,9 @@ pub enum Mode {
AStar, AStar,
} }
impl Mode { impl Mode {
pub fn parse(s: &str) -> Result<Mode, String> { pub fn parse(s: &str) -> Result<Mode, String> {
let s=s.to_lowercase(); let s = s.to_lowercase();
match s.as_ref() { match s.as_ref() {
"bfs" => Ok(Mode::BFS), "bfs" => Ok(Mode::BFS),
"greedy" => Ok(Mode::Greedy), "greedy" => Ok(Mode::Greedy),
@ -160,8 +175,8 @@ impl LineCache {
} }
pub fn get(&mut self, id: u32) -> Option<System> { pub fn get(&mut self, id: u32) -> Option<System> {
let pos = self.cache[id as usize]; let pos = self.cache[id as usize];
self.file.seek(std::io::SeekFrom::Start(pos)).unwrap(); self.file.seek(std::io::SeekFrom::Start(pos)).ok()?;
let rec = Self::read_record(&mut self.file).unwrap(); let rec = Self::read_record(&mut self.file)?;
let sys: SystemSerde = rec.deserialize(self.header.as_ref()).unwrap(); let sys: SystemSerde = rec.deserialize(self.header.as_ref()).unwrap();
Some(sys.build()) Some(sys.build())
} }
@ -175,18 +190,26 @@ pub struct Router {
range: f32, range: f32,
primary_only: bool, primary_only: bool,
path: PathBuf, path: PathBuf,
callback: Box<dyn Fn(&SearchState) -> PyResult<PyObject>> radius_mult: f32,
callback: Box<dyn Fn(&SearchState) -> PyResult<PyObject>>,
} }
impl Router { impl Router {
pub fn new(path: &PathBuf, range: f32, primary_only: bool,callback: Box<dyn Fn(&SearchState) -> PyResult<PyObject>>) -> Result<Self,String> { pub fn new(
path: &PathBuf,
range: f32,
radius_mult: f32,
primary_only: bool,
callback: Box<dyn Fn(&SearchState) -> PyResult<PyObject>>,
) -> Result<Self, String> {
let mut scoopable = FnvHashSet::default(); let mut scoopable = FnvHashSet::default();
let mut reader = match csv::ReaderBuilder::new().from_path(path) { let mut reader = match csv::ReaderBuilder::new().from_path(path) {
Ok(rdr) => rdr, Ok(rdr) => rdr,
Err(e) => { Err(e) => {
return Err(format!("Error opening {}: {}", path.to_str().unwrap(), e).to_string()); return Err(format!("Error opening {}: {}", path.to_str().unwrap(), e));
} }
}; };
let t_load = Instant::now();
println!("Loading {}...", path.to_str().unwrap()); println!("Loading {}...", path.to_str().unwrap());
let systems: Vec<System> = reader let systems: Vec<System> = reader
.deserialize::<SystemSerde>() .deserialize::<SystemSerde>()
@ -220,25 +243,54 @@ impl Router {
primary_only, primary_only,
cache: LineCache::new(path), cache: LineCache::new(path),
path: path.clone(), path: path.clone(),
callback: callback, callback,
radius_mult,
}; };
println!(
"{} Systems loaded in {}",
ret.tree.size(),
format_duration(t_load.elapsed())
);
Ok(ret) Ok(ret)
} }
pub fn from_file(filename: &PathBuf,callback: Box<dyn Fn(&SearchState) -> PyResult<PyObject>>) -> Result<(PathBuf, Self),String> { pub fn from_file(
let mut reader = BufReader::new(File::open(&filename).unwrap()); filename: &PathBuf,
callback: Box<dyn Fn(&SearchState) -> PyResult<PyObject>>,
) -> Result<(PathBuf, Self), String> {
let t_load = Instant::now();
let mut reader = BufReader::new(match File::open(&filename) {
Ok(fh) => fh,
Err(e) => {
return Err(format!(
"Error opening file {}: {}",
filename.to_str().unwrap(),
e
))
}
});
println!("Loading {}", filename.to_str().unwrap());
let (primary, range, file_hash, path, route_tree): ( let (primary, range, file_hash, path, route_tree): (
bool, bool,
f32, f32,
Vec<u8>, Vec<u8>,
String, String,
FnvHashMap<u32, u32>, FnvHashMap<u32, u32>,
) = bincode::deserialize_from(&mut reader).unwrap(); ) = match bincode::deserialize_from(&mut reader) {
Ok(res) => res,
Err(e) => {
return Err(format!(
"Error loading file {}: {}",
filename.to_str().unwrap(),
e
))
}
};
let path = PathBuf::from(path); let path = PathBuf::from(path);
if hash_file(&path) != file_hash { if hash_file(&path) != file_hash {
return Err("File hash mismatch!".to_string()); return Err("File hash mismatch!".to_string());
} }
let cache = LineCache::new(&path); let cache = LineCache::new(&path).ok();
Ok(( Ok((
path.clone(), path.clone(),
Self { Self {
@ -249,14 +301,12 @@ impl Router {
cache, cache,
primary_only: primary, primary_only: primary,
path, path,
callback callback,
radius_mult: 0f32,
}, },
)) ))
} }
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> { fn points_in_sphere(&self, center: &[f32; 3], radius: f32) -> impl Iterator<Item = &System> {
self.tree.locate_within_distance(*center, radius * radius) self.tree.locate_within_distance(*center, radius * radius)
} }
@ -265,18 +315,23 @@ impl Router {
self.points_in_sphere(&sys.pos, sys.mult * r) self.points_in_sphere(&sys.pos, sys.mult * r)
} }
fn valid(&self, sys: &System) -> bool { fn valid(&self, sys: &System, src: &System, dst: &System) -> bool {
self.scoopable.contains(&sys.id) let scoopable = self.scoopable.contains(&sys.id);
if self.radius_mult == 0.0 {
return scoopable;
}
let df = src.distp(dst);
return (sys.distp(src) + sys.distp(dst)) < (df * (1.0 + self.radius_mult));
} }
pub fn best_name_multiroute( pub fn best_multiroute(
&self, &self,
waypoints: &[String], waypoints: &Vec<System>,
range: f32, range: f32,
keep: (bool,bool), keep: (bool, bool),
mode: Mode, mode: Mode,
factor: f32, factor: f32,
) -> Result<Vec<System>,String> { ) -> Result<Vec<System>, String> {
let mut best_score: f32 = std::f32::MAX; let mut best_score: f32 = std::f32::MAX;
let mut waypoints = waypoints.to_owned(); let mut waypoints = waypoints.to_owned();
let mut best_permutation_waypoints = waypoints.to_owned(); let mut best_permutation_waypoints = waypoints.to_owned();
@ -287,17 +342,12 @@ impl Router {
loop { loop {
let c_first = waypoints.first().cloned(); let c_first = waypoints.first().cloned();
let c_last = waypoints.last().cloned(); let c_last = waypoints.last().cloned();
let valid = (keep.0 && (c_first == first)) && (keep.1 && (c_last==last)); let valid = (keep.0 && (c_first == first)) && (keep.1 && (c_last == last));
if valid { if valid {
let mut total_d = 0.0; let mut total_d = 0.0;
for pair in waypoints.windows(2) { for pair in waypoints.windows(2) {
match pair { match pair {
[src, dst] => { [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); total_d += src.distp2(dst);
} }
_ => return Err("Invalid routing parameters!".to_string()), _ => return Err("Invalid routing parameters!".to_string()),
@ -313,35 +363,19 @@ impl Router {
} }
} }
println!("Best permutation: {:?}", best_permutation_waypoints); println!("Best permutation: {:?}", best_permutation_waypoints);
self.name_multiroute(&best_permutation_waypoints, range, mode, factor) self.multiroute(&best_permutation_waypoints, range, mode, factor)
} }
pub fn name_multiroute(
&self,
waypoints: &[String],
range: f32,
mode: Mode,
factor: f32,
) -> Result<Vec<System>,String> {
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( pub fn multiroute(
&self, &self,
waypoints: &[(&String, [f32; 3])], waypoints: &Vec<System>,
range: f32, range: f32,
mode: Mode, mode: Mode,
factor: f32, factor: f32,
) -> Result<Vec<System>,String> { ) -> Result<Vec<System>, String> {
let mut route: Vec<System> = Vec::new(); let mut route: Vec<System> = Vec::new();
for pair in waypoints.windows(2) { for pair in waypoints.windows(2) {
match *pair { match pair.clone() {
[src, dst] => { [src, dst] => {
let block = match mode { let block = match mode {
Mode::BFS => self.route_bfs(&src, &dst, range)?, Mode::BFS => self.route_bfs(&src, &dst, range)?,
@ -358,56 +392,88 @@ impl Router {
} }
} }
} }
_ => return Err("Invalid routing parameters!".to_string()), _ => {
return Err("Invalid routing parameters!".to_owned());
}
} }
} }
Ok(route) Ok(route)
} }
fn name_to_systems(&self, name: &str) -> Result<Vec<&System>,String> { fn resolve_systems(&self, systems: &[SysEntry]) -> Result<Vec<System>, String> {
let mut ret = Vec::new();
let mut sys_by_id: FnvHashMap<u32, &System> = FnvHashMap::default();
let mut sys_by_name: FnvHashMap<String, &System> = FnvHashMap::default();
for sys in &self.tree { for sys in &self.tree {
if sys.system == name { for ent in systems {
return Ok(self.neighbours(&sys, 0.0).collect()); match ent {
SysEntry::ID(i) => {
let i = *i;
if sys.id == i {
sys_by_id.insert(i, sys);
}
}
SysEntry::Name(n) => {
if &sys.body == n || &sys.system == n {
sys_by_name.insert(n.to_string(), sys);
}
}
}
} }
} }
Err(format!("System not found: \"{}\"", name)) for ent in systems {
match ent {
SysEntry::ID(i) => match sys_by_id.get(i) {
Some(sys) => ret.push(sys.clone().clone()),
None => {
return Err(format!("System: {:?} not found", ent));
}
},
SysEntry::Name(n) => match sys_by_name.get(n) {
Some(sys) => ret.push(sys.clone().clone()),
None => {
return Err(format!("System: {:?} not found", ent));
}
},
}
}
Ok(ret)
} }
pub fn route_astar( pub fn route_astar(
&self, &self,
src: &(&String, [f32; 3]), src: &System,
dst: &(&String, [f32; 3]), dst: &System,
range: f32, range: f32,
factor: f32, factor: f32,
) -> Result<Vec<System>,String> { ) -> Result<Vec<System>, String> {
if factor == 0.0 { if factor == 0.0 {
return self.route_bfs(src, dst, range); return self.route_bfs(src, dst, range);
} }
let (src_name, src) = src; let src_name = src.system.clone();
let (dst_name, dst) = dst; let dst_name = dst.system.clone();
let start_sys = self.closest(src); let start_sys = src;
let goal_sys = self.closest(dst); let goal_sys = dst;
let d_total = dist(&start_sys.pos,&goal_sys.pos); let d_total = dist(&start_sys.pos, &goal_sys.pos);
let mut d_rem=d_total; let mut d_rem = d_total;
let mut state=SearchState { let mut state = SearchState {
mode:"A-Star".into(), mode: "A-Star".into(),
depth:0, depth: 0,
queue_size:0, queue_size: 0,
d_rem: d_total, d_rem: d_total,
d_total: d_total, d_total,
prc_done: 0.0, prc_done: 0.0,
n_seen:0, n_seen: 0,
prc_seen: 0.0, prc_seen: 0.0,
body: start_sys.body.clone(), body: start_sys.body.clone(),
system: start_sys.system.clone() system: start_sys.system.clone(),
}; };
let total = self.tree.size() as f32; let total = self.tree.size() as f32;
let t_start = Instant::now(); let mut t_last = Instant::now();
let mut prev = FnvHashMap::default(); let mut prev = FnvHashMap::default();
let mut seen = FnvHashSet::default(); let mut seen = FnvHashSet::default();
let mut found = false; let mut found = false;
let mut maxd = 0;
let mut queue: Vec<(usize, usize, &System)> = Vec::new(); let mut queue: Vec<(usize, usize, &System)> = Vec::new();
queue.push(( queue.push((
0, // depth 0, // depth
@ -417,31 +483,22 @@ impl Router {
seen.insert(start_sys.id); seen.insert(start_sys.id);
while !(queue.is_empty() || found) { while !(queue.is_empty() || found) {
while let Some((depth, _, sys)) = queue.pop() { while let Some((depth, _, sys)) = queue.pop() {
if (depth+1) > maxd { if t_last.elapsed().as_millis() > 100 {
maxd = depth+1; t_last = Instant::now();
state.depth=depth; state.depth = depth;
state.queue_size=queue.len(); state.queue_size = queue.len();
state.prc_done=((d_total-d_rem)*100f32) / d_total; state.prc_done = ((d_total - d_rem) * 100f32) / d_total;
state.d_rem=d_rem; state.d_rem = d_rem;
state.n_seen=seen.len(); state.n_seen = seen.len();
state.prc_seen=((seen.len()*100) as f32) / total; state.prc_seen = ((seen.len() * 100) as f32) / total;
state.body=sys.body.clone(); state.body = sys.body.clone();
state.system=sys.system.clone(); state.system = sys.system.clone();
match (self.callback)(&state) { match (self.callback)(&state) {
Ok(_) => (), Ok(_) => (),
Err(e) => { Err(e) => {
return Err(format!("{:?}",e).to_string()); return Err(format!("{:?}", e).to_string());
} }
}; };
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 { if sys.id == goal_sys.id {
found = true; found = true;
@ -449,16 +506,15 @@ impl Router {
} }
queue.extend( queue.extend(
self.neighbours(&sys, range) self.neighbours(&sys, range)
.filter(|&nb| (self.valid(nb) || (nb.id == goal_sys.id))) .filter(|&nb| (self.valid(nb, &src, &dst) || (nb.id == goal_sys.id)))
.filter(|&nb| seen.insert(nb.id)) .filter(|&nb| seen.insert(nb.id))
.map(|nb| { .map(|nb| {
prev.insert(nb.id, sys); prev.insert(nb.id, sys);
let d_g = (nb.distp(goal_sys) / range) as usize; let d_g=nb.distp(goal_sys);
let dist = dist(&nb.pos, &goal_sys.pos); if d_g<d_rem {
if dist < d_rem { d_rem=d_g;
d_rem = dist;
} }
(depth + 1, d_g, nb) (depth + 1, (d_g / range) as usize, nb)
}), }),
); );
queue.sort_by(|b, a| { queue.sort_by(|b, a| {
@ -475,7 +531,7 @@ impl Router {
println!(); println!();
if !found { if !found {
return Err(format!("No route from {} to {} found!", src_name, dst_name).to_string()); return Err(format!("No route from {} to {} found!", src_name, dst_name));
} }
let mut v: Vec<System> = Vec::new(); let mut v: Vec<System> = Vec::new();
let mut curr_sys = goal_sys; let mut curr_sys = goal_sys;
@ -494,54 +550,54 @@ impl Router {
pub fn route_greedy( pub fn route_greedy(
&self, &self,
src: &(&String, [f32; 3]), src: &System,
dst: &(&String, [f32; 3]), dst: &System,
range: f32, range: f32,
) -> Result<Vec<System>,String> { ) -> Result<Vec<System>, String> {
let (src_name, src) = src; let src_name = src.system.clone();
let (dst_name, dst) = dst; let dst_name = dst.system.clone();
let start_sys = self.closest(src); let start_sys = src;
let goal_sys = self.closest(dst); let goal_sys = dst;
let d_total = dist(&start_sys.pos, &goal_sys.pos); let d_total = dist(&start_sys.pos, &goal_sys.pos);
let mut d_rem=d_total; let mut d_rem = d_total;
let mut state=SearchState { let mut state = SearchState {
mode:"Greedy".into(), mode: "Greedy".into(),
depth:0, depth: 0,
queue_size:0, queue_size: 0,
d_rem: d_total, d_rem: d_total,
d_total: d_total, d_total,
prc_done: 0.0, prc_done: 0.0,
n_seen:0, n_seen: 0,
prc_seen: 0.0, prc_seen: 0.0,
body:start_sys.body.clone(), body: start_sys.body.clone(),
system:start_sys.system.clone(), system: start_sys.system.clone(),
}; };
let total = self.tree.size() as f32; let total = self.tree.size() as f32;
let mut t_last = Instant::now();
let mut prev = FnvHashMap::default(); let mut prev = FnvHashMap::default();
let mut seen = FnvHashSet::default(); let mut seen = FnvHashSet::default();
let mut found = false; let mut found = false;
let mut maxd = 0;
let mut queue: Vec<(f32, f32, usize, &System)> = Vec::new(); let mut queue: Vec<(f32, f32, usize, &System)> = Vec::new();
queue.push((-goal_sys.mult, start_sys.distp2(goal_sys), 0, &start_sys)); queue.push((-goal_sys.mult, start_sys.distp(goal_sys), 0, &start_sys));
seen.insert(start_sys.id); seen.insert(start_sys.id);
while !(queue.is_empty() || found) { while !(queue.is_empty() || found) {
while let Some((_, _, depth, sys)) = queue.pop() { while let Some((_, _, depth, sys)) = queue.pop() {
if (depth+1) > maxd { if t_last.elapsed().as_millis() > 100 {
state.depth=depth; t_last = Instant::now();
state.queue_size=queue.len(); state.depth = depth;
state.prc_done=((d_total-d_rem)*100f32) / d_total; state.queue_size = queue.len();
state.d_rem=d_rem; state.prc_done = ((d_total - d_rem) * 100f32) / d_total;
state.n_seen=seen.len(); state.d_rem = d_rem;
state.prc_seen=((seen.len()*100) as f32) / total; state.n_seen = seen.len();
state.body=sys.body.clone(); state.prc_seen = ((seen.len() * 100) as f32) / total;
state.system=sys.system.clone(); state.body = sys.body.clone();
state.system = sys.system.clone();
match (self.callback)(&state) { match (self.callback)(&state) {
Ok(_) => (), Ok(_) => (),
Err(e) => { Err(e) => {
return Err(format!("{:?}",e).to_string()); return Err(format!("{:?}", e).to_string());
} }
}; };
maxd = depth+1;
} }
if sys.id == goal_sys.id { if sys.id == goal_sys.id {
found = true; found = true;
@ -549,15 +605,15 @@ impl Router {
} }
queue.extend( queue.extend(
self.neighbours(&sys, range) self.neighbours(&sys, range)
.filter(|&nb| (self.valid(nb) || (nb.id == goal_sys.id))) .filter(|&nb| (self.valid(nb, &src, &dst) || (nb.id == goal_sys.id)))
.filter(|&nb| seen.insert(nb.id)) .filter(|&nb| seen.insert(nb.id))
.map(|nb| { .map(|nb| {
prev.insert(nb.id, sys); prev.insert(nb.id, sys);
let dist = dist(&nb.pos, &goal_sys.pos); let d_g=nb.distp(goal_sys);
if dist < d_rem { if d_g<d_rem {
d_rem = dist; d_rem=d_g;
} }
(-nb.mult, nb.distp2(goal_sys), depth + 1, nb) (-nb.mult, d_g, depth + 1, nb)
}), }),
); );
queue.sort_by(|a, b| fcmp(a.0, b.0).then(fcmp(a.1, b.1))); queue.sort_by(|a, b| fcmp(a.0, b.0).then(fcmp(a.1, b.1)));
@ -565,7 +621,7 @@ impl Router {
} }
} }
if !found { if !found {
return Err(format!("No route from {} to {} found!", src_name, dst_name).to_string()); return Err(format!("No route from {} to {} found!", src_name, dst_name));
} }
let mut v: Vec<System> = Vec::new(); let mut v: Vec<System> = Vec::new();
let mut curr_sys = goal_sys; let mut curr_sys = goal_sys;
@ -582,10 +638,7 @@ impl Router {
Ok(v) Ok(v)
} }
pub fn precompute(&mut self, src: &str) -> Result<(),String> { pub fn precompute(&mut self, src: &System) -> Result<(), String> {
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();
let total = self.tree.size() as f32; let total = self.tree.size() as f32;
let t_start = Instant::now(); let t_start = Instant::now();
let mut prev = FnvHashMap::default(); let mut prev = FnvHashMap::default();
@ -593,8 +646,8 @@ impl Router {
let mut depth = 0; let mut depth = 0;
let mut queue: VecDeque<(usize, &System)> = VecDeque::new(); let mut queue: VecDeque<(usize, &System)> = VecDeque::new();
let mut queue_next: VecDeque<(usize, &System)> = VecDeque::new(); let mut queue_next: VecDeque<(usize, &System)> = VecDeque::new();
queue.push_front((0, &sys)); queue.push_front((0, &src));
seen.insert(sys.id); seen.insert(src.id);
while !queue.is_empty() { while !queue.is_empty() {
print!( print!(
"[{}] Depth: {}, Queue: {}, Seen: {} ({:.02}%) \r", "[{}] Depth: {}, Queue: {}, Seen: {} ({:.02}%) \r",
@ -622,7 +675,7 @@ impl Router {
self.route_tree = Some(prev); self.route_tree = Some(prev);
let ofn = format!( let ofn = format!(
"{}_{}{}.router", "{}_{}{}.router",
src.replace("*", "").replace(" ", "_"), src.system.replace("*", "").replace(" ", "_"),
self.range, self.range,
if self.primary_only { "_primary" } else { "" } if self.primary_only { "_primary" } else { "" }
); );
@ -634,13 +687,17 @@ impl Router {
String::from(self.path.to_str().unwrap()), String::from(self.path.to_str().unwrap()),
self.route_tree.as_ref().unwrap(), self.route_tree.as_ref().unwrap(),
); );
return match bincode::serialize_into(&mut out_fh, &data) { match bincode::serialize_into(&mut out_fh, &data) {
Ok(_) => Ok(()), Ok(_) => Ok(()),
Err(e) => Err(format!("Error: {}",e).to_string()) Err(e) => Err(format!("Error: {}", e).to_string()),
}; }
} }
fn get_systems_by_ids(&mut self, path: &PathBuf, ids: &[u32]) -> Result<FnvHashMap<u32, System>,String> { fn get_systems_by_ids(
&mut self,
path: &PathBuf,
ids: &[u32],
) -> Result<FnvHashMap<u32, System>, String> {
let mut ret = FnvHashMap::default(); let mut ret = FnvHashMap::default();
if let Some(c) = &mut self.cache.as_mut() { if let Some(c) = &mut self.cache.as_mut() {
let mut missing = false; let mut missing = false;
@ -659,13 +716,12 @@ impl Router {
return Ok(ret); return Ok(ret);
} }
} }
let mut reader = match csv::ReaderBuilder::new() let mut reader = match csv::ReaderBuilder::new().from_path(path) {
.from_path(path) { Ok(reader) => reader,
Ok(reader) => reader, Err(e) => {
Err(e) => { return Err(format!("Error opening {}: {}", path.to_str().unwrap(), e));
return Err(format!("Error opening {}: {}", path.to_str().unwrap(), e)); }
} };
};
reader reader
.deserialize::<SystemSerde>() .deserialize::<SystemSerde>()
.map(|res| res.unwrap()) .map(|res| res.unwrap())
@ -674,30 +730,20 @@ impl Router {
ret.insert(sys.id, sys.build()); ret.insert(sys.id, sys.build());
}) })
.count(); .count();
for id in ids {
if !ret.contains_key(&id) {
return Err(format!("ID {} not found", id));
}
}
Ok(ret) Ok(ret)
} }
fn get_system_by_name(path: &PathBuf, name: &str) -> Result<System,String> { pub fn route_to(
// TODO: Fuzzy search (https://github.com/andylokandy/simsearch-rs) &mut self,
let mut reader = csv::ReaderBuilder::new() dst: &System,
.from_path(path) systems_path: &PathBuf,
.unwrap_or_else(|e| { ) -> Result<Vec<System>, String> {
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);
match sys {
Some(system) => Ok(system.build()),
None => Err(format!("System {} not found!",name).to_string())
}
}
pub fn route_to(&mut self, dst: &str, systems_path: &PathBuf) -> Result<Vec<System>,String> {
let prev = self.route_tree.as_ref().unwrap(); let prev = self.route_tree.as_ref().unwrap();
let dst = Self::get_system_by_name(&systems_path, dst)?;
if !prev.contains_key(&dst.id) { if !prev.contains_key(&dst.id) {
return Err(format!("System-ID {} not found", dst.id).to_string()); return Err(format!("System-ID {} not found", dst.id).to_string());
}; };
@ -719,7 +765,7 @@ impl Router {
let sys = match id_map.get(&sys_id) { let sys = match id_map.get(&sys_id) {
Some(sys) => sys, Some(sys) => sys,
None => { None => {
return Err(format!("System-ID {} not found!",sys_id)); return Err(format!("System-ID {} not found!", sys_id));
} }
}; };
v.push(sys.clone()) v.push(sys.clone())
@ -729,29 +775,29 @@ impl Router {
pub fn route_bfs( pub fn route_bfs(
&self, &self,
src: &(&String, [f32; 3]), start_sys: &System,
dst: &(&String, [f32; 3]), goal_sys: &System,
range: f32, range: f32,
) -> Result<Vec<System>,String> { ) -> Result<Vec<System>, String> {
println!("Running BFS"); println!("Running BFS");
let (src_name, src) = src; let src_name = start_sys.system.clone();
let (dst_name, dst) = dst; let dst_name = goal_sys.system.clone();
let start_sys = self.closest(src);
let goal_sys = self.closest(dst);
let d_total = dist(&start_sys.pos, &goal_sys.pos); let d_total = dist(&start_sys.pos, &goal_sys.pos);
let mut state=SearchState { let mut d_rem = d_total;
mode:"BFS".into(), let mut state = SearchState {
depth:0, mode: "BFS".into(),
queue_size:0, depth: 0,
d_rem: d_total, queue_size: 0,
d_total: d_total, d_rem,
d_total,
prc_done: 0.0, prc_done: 0.0,
n_seen:0, n_seen: 0,
prc_seen: 0.0, prc_seen: 0.0,
system: start_sys.system.clone(), system: start_sys.system.clone(),
body: start_sys.body.clone() body: start_sys.body.clone(),
}; };
{ {
let d = dist(&start_sys.pos, &goal_sys.pos);
println!("Plotting route from {} to {}...", src_name, dst_name); println!("Plotting route from {} to {}...", src_name, dst_name);
println!( println!(
"Jump Range: {} Ly, Distance: {} Ly, Estimated Jumps: {}", "Jump Range: {} Ly, Distance: {} Ly, Estimated Jumps: {}",
@ -765,41 +811,47 @@ impl Router {
let mut seen = FnvHashSet::default(); let mut seen = FnvHashSet::default();
let mut depth = 0; let mut depth = 0;
let mut found = false; let mut found = false;
let mut t_last = Instant::now();
let mut queue: VecDeque<(usize, &System)> = VecDeque::new(); let mut queue: VecDeque<(usize, &System)> = VecDeque::new();
let mut queue_next: VecDeque<(usize, &System)> = VecDeque::new(); let mut queue_next: VecDeque<(usize, &System)> = VecDeque::new();
let mut d_rem = dist(&start_sys.pos, &goal_sys.pos); let mut d_rem = dist(&start_sys.pos, &goal_sys.pos);
queue.push_front((0, &start_sys)); queue.push_front((0, &start_sys));
seen.insert(start_sys.id); seen.insert(start_sys.id);
while !(queue.is_empty() || found) { while !(queue.is_empty() || found) {
state.depth=depth;
state.queue_size=queue.len();
state.prc_done=((d_total-d_rem)*100f32) / d_total;
state.d_rem=d_rem;
state.n_seen=seen.len();
state.prc_seen=((seen.len()*100) as f32) / total;
{
let s=queue.get(0).unwrap().1;
state.system=s.system.clone();
state.body=s.body.clone();
}
match (self.callback)(&state) {
Ok(_) => (),
Err(e) => {
return Err(format!("{:?}",e).to_string());
}
};
while let Some((d, sys)) = queue.pop_front() { while let Some((d, sys)) = queue.pop_front() {
if sys.id == goal_sys.id { if sys.id == goal_sys.id {
found = true; found = true;
break; break;
} }
if t_last.elapsed().as_millis() > 100 {
state.depth = depth;
state.queue_size = queue.len();
state.prc_done = ((d_total - d_rem) * 100f32) / d_total;
state.d_rem = d_rem;
state.n_seen = seen.len();
state.prc_seen = ((seen.len() * 100) as f32) / total;
{
let s = queue.get(0).unwrap().1;
state.system = s.system.clone();
state.body = s.body.clone();
}
match (self.callback)(&state) {
Ok(_) => (),
Err(e) => {
return Err(format!("{:?}", e).to_string());
}
};
t_last = Instant::now();
}
queue_next.extend( queue_next.extend(
self.neighbours(&sys, range) self.neighbours(&sys, range)
.filter(|&nb| (self.valid(nb) || (nb.id == goal_sys.id))) .filter(|&nb| {
(self.valid(nb, &start_sys, &goal_sys) || (nb.id == goal_sys.id))
})
.filter(|&nb| seen.insert(nb.id)) .filter(|&nb| seen.insert(nb.id))
.map(|nb| { .map(|nb| {
prev.insert(nb.id, sys); prev.insert(nb.id, sys);
let dist = dist(&nb.pos, &goal_sys.pos); let dist = nb.distp(goal_sys);
if dist < d_rem { if dist < d_rem {
d_rem = dist; d_rem = dist;
} }
@ -813,7 +865,7 @@ impl Router {
println!(); println!();
println!(); println!();
if !found { if !found {
return Err(format!("No route from {} to {} found!", src_name, dst_name).to_string()); return Err(format!("No route from {} to {} found!", src_name, dst_name));
} }
let mut v: Vec<System> = Vec::new(); let mut v: Vec<System> = Vec::new();
let mut curr_sys = goal_sys; let mut curr_sys = goal_sys;
@ -830,54 +882,71 @@ impl Router {
Ok(v) Ok(v)
} }
} }
pub fn route(opts: RouteOpts) -> Result<Option<Vec<System>>,String> { pub fn route(opts: RouteOpts) -> Result<Option<Vec<System>>, String> {
if opts.systems.is_empty() { if opts.systems.is_empty() {
return if opts.precomp_file.is_some() { if opts.precomp_file.is_some() {
Err("Error: Please specify exatly one system".to_string()) return Err("Error: Please specify exatly one system".to_owned());
} else if opts.precompute { } else if opts.precompute {
Err("Error: Please specify at least one system".to_string()) return Err("Error: Please specify at least one system".to_owned());
} else { } else {
Err("Error: Please specify at least two systems".to_string()) return Err("Error: Please specify at least two systems".to_owned());
} };
} }
let mut path = opts.file_path; let mut path = opts.file_path;
let mut router: Router = if opts.precomp_file.is_some() { let mut router: Router = if opts.precomp_file.is_some() {
let (path_,ret) = Router::from_file(&opts.precomp_file.clone().unwrap(),Box::new(opts.callback))?; let (path_, ret) =
path=path_; Router::from_file(&opts.precomp_file.clone().unwrap(), Box::new(opts.callback))?;
path = path_;
ret ret
} else if opts.range.is_some() { } else if opts.range.is_some() {
Router::new(&path, opts.range.unwrap(), opts.primary, Box::new(opts.callback))? Router::new(
&path,
opts.range.unwrap(),
opts.radius_mult,
opts.primary,
Box::new(opts.callback),
)?
} else { } else {
return Err("Please specify a jump range!".to_string()); Router::new(
&path,
opts.range.unwrap(),
opts.radius_mult,
opts.primary,
opts.callback,
)?
}; };
let systems: Vec<System> = router
.resolve_systems(&opts.systems)?
.iter()
.map(|sys| sys.clone())
.collect();
if opts.precompute { if opts.precompute {
for sys in opts.systems { for sys in systems {
router.route_tree = None; router.route_tree = None;
router.precompute(&sys)?; router.precompute(&sys)?;
} }
return Ok(None) return Ok(None);
} }
let route = if router.route_tree.is_some() { let route = if router.route_tree.is_some() {
router.route_to(opts.systems.first().unwrap(), &path)? router.route_to(systems.first().unwrap(), &path)?
} else if opts.permute { } else if opts.permute {
router.best_name_multiroute( router.best_multiroute(
&opts.systems, &systems,
opts.range.unwrap(), opts.range.unwrap(),
(opts.keep_first,opts.keep_last), (opts.keep_first, opts.keep_last),
opts.mode, opts.mode,
opts.factor.unwrap_or(1.0), opts.factor.unwrap_or(1.0),
)? )?
} else { } else {
router.name_multiroute( router.multiroute(
&opts.systems, &systems,
opts.range.unwrap(), opts.range.unwrap(),
opts.mode, opts.mode,
opts.factor.unwrap_or(1.0), opts.factor.unwrap_or(1.0),
)? )?
}; };
if route.is_empty() { if route.is_empty() {
return Err("No route found!".to_string()) return Err("No route found!".to_string());
} }
return Ok(Some(route)); Ok(Some(route))
} }

View file

@ -18,7 +18,14 @@ setup(
], ],
packages=["ed_lrr_gui"], packages=["ed_lrr_gui"],
entry_points={"console_scripts": ["ed_lrr_gui=ed_lrr_gui.__main__:main"]}, entry_points={"console_scripts": ["ed_lrr_gui=ed_lrr_gui.__main__:main"]},
install_requires=["PyQt5", "appdirs", "PyYAML", "requests", "python-dateutil"], install_requires=[
"PyQt5",
"appdirs",
"PyYAML",
"requests",
"python-dateutil",
"pyperclip",
],
include_package_data=True, include_package_data=True,
zip_safe=False, zip_safe=False,
) )

4
test.bat Normal file
View file

@ -0,0 +1,4 @@
python build_gui.py
pip uninstall -y ed_lrr_gui
pip install -e .
ed_lrr_gui