Compare commits

...

No commits in common. "master" and "pyqt_gui" have entirely different histories.

54 changed files with 6409 additions and 1697 deletions

View File

@ -1,2 +0,0 @@
[build]
rustflags = ["-C", "target-cpu=native"]

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

@ -0,0 +1,40 @@
{{ if .Versions -}}
## [Unreleased]
{{ if .Unreleased.CommitGroups -}}
{{ range .Unreleased.CommitGroups -}}
### {{ .Title }}
{{ range .Commits -}}
- {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }} [{{.Hash.Short}}]({{ $.Info.RepositoryURL }}/commit/{{ .Hash.Short }})
{{ end }}
{{ end -}}
{{ end -}}
{{ end -}}
{{ range .Versions }}
## {{ if .Tag.Previous }}[{{ .Tag.Name }}]{{ else }}{{ .Tag.Name }}{{ end }} - {{ datetime "2006-01-02" .Tag.Date }}
{{ range .CommitGroups -}}
### {{ .Title }}
{{ range .Commits -}}
- {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }} [{{.Hash.Short}}]({{ $.Info.RepositoryURL }}/commit/{{ .Hash.Short }})
{{ 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 -}}

34
.chglog/config.yml Normal file
View File

@ -0,0 +1,34 @@
style: gitlab
template: CHANGELOG.tpl.md
info:
title: CHANGELOG
repository_url: https://gitlab.com/Earthnuker/ed_lrr
options:
commits:
filters:
Type:
- feat
- fix
- perf
- refactor
- misc
- other
- docs
commit_groups:
title_maps:
feat: Features
fix: Bug Fixes
perf: Performance Improvements
refactor: Code Refactoring
misc: Miscellaneous
other: Other
docs: Documentation
header:
pattern: "^(\\w*)(?:\\(([\\w\\$\\.\\-\\*\\s]*)\\))?\\:\\s(.*)$"
pattern_maps:
- Type
- Scope
- Subject
notes:
keywords:
- BREAKING CHANGE

25
.gitignore vendored
View File

@ -1,9 +1,24 @@
/target
rust/target
rust/.history/
**/*.rs.bk
*.tmp
*.idx
.vscode/**
*.csv
*.router
dumps/*.json
plot.py
*.tmp
*.idx
plot.py
*.tmp
*.idx
*.pyd
__pycache__
*.egg-info
build
*.pdf
.history
.tox
pip-wheel-metadata
.eggs/
exe/
installer/Output/
workspace.code-workspace
ed_lrr_gui/web/jobs.db

View File

@ -1,26 +0,0 @@
# This file is a template, and might need editing before it works on your project.
# Official language image. Look for the different tagged releases at:
# https://hub.docker.com/r/library/rust/tags/
image: "rust:latest"
# Optional: Pick zero or more services to be used on all builds.
# Only needed when using a docker container to run your tests in.
# Check out: http://docs.gitlab.com/ce/ci/docker/using_docker_images.html#what-is-a-service
# services:
# - mysql:latest
# - redis:latest
# - postgres:latest
# Optional: Install a C compiler, cmake and git into the container.
# You will often need this when you (or any of your dependencies) depends on C code.
before_script:
- apt-get update -yqq
- apt-get install -yqq --no-install-recommends build-essential
- rustup update nightly
- rustup default nightly
# Use cargo to test the project
test:cargo:
script:
- rustc --version && cargo --version # Print version info for debugging
- cargo build --release

264
CHANGELOG.md Normal file
View File

@ -0,0 +1,264 @@
## [Unreleased]
## [v0.24.0] - 2019-10-23
### Features
- **tests:** Add pytest.ini for pytest-qt [eb43ca8](https://gitlab.com/Earthnuker/ed_lrr/commit/eb43ca8)
## [v0.23.0] - 2019-10-23
### Documentation
- **readme:** Update README with more infos [634af75](https://gitlab.com/Earthnuker/ed_lrr/commit/634af75)
### Features
- **setup.py:** Update add dependencies for HTTP API [45c11da](https://gitlab.com/Earthnuker/ed_lrr/commit/45c11da)
## [v0.22.0] - 2019-10-23
### Features
- **tox:** Add more python versions to test against [3115f9d](https://gitlab.com/Earthnuker/ed_lrr/commit/3115f9d)
## [v0.21.0] - 2019-10-23
### Features
- **html_export:** Add basic HTML-Export using Jinja2 template [bb2ee8c](https://gitlab.com/Earthnuker/ed_lrr/commit/bb2ee8c)
## [v0.20.0] - 2019-10-23
### Features
- **route_progress:** minor change to progress dialog message [35fc135](https://gitlab.com/Earthnuker/ed_lrr/commit/35fc135)
## [v0.19.1] - 2019-10-23
### Bug Fixes
- **config:** Add missing defaults [30dbd24](https://gitlab.com/Earthnuker/ed_lrr/commit/30dbd24)
### Documentation
- Update CHANGELOG.md and README.md [38acfc7](https://gitlab.com/Earthnuker/ed_lrr/commit/38acfc7)
## [v0.19.0] - 2019-09-28
### Features
- **config:** impelemt save and load to GUI [65fe131](https://gitlab.com/Earthnuker/ed_lrr/commit/65fe131)
## [v0.18.0] - 2019-09-28
### Features
- **GUI:** implement preprocessing [f34d37a](https://gitlab.com/Earthnuker/ed_lrr/commit/f34d37a)
## [v0.17.0] - 2019-09-28
### Documentation
- Update TODO list in readme [4663d4e](https://gitlab.com/Earthnuker/ed_lrr/commit/4663d4e)
### Features
- **installer:** switch from LZMA to LZMA2 [3ee952e](https://gitlab.com/Earthnuker/ed_lrr/commit/3ee952e)
## [v0.16.0] - 2019-09-28
### Features
- **build scripts:** skip .history folder when building UI files [92bd1b1](https://gitlab.com/Earthnuker/ed_lrr/commit/92bd1b1)
## [v0.15.0] - 2019-09-28
### Features
- **config:** update config format [9ec4687](https://gitlab.com/Earthnuker/ed_lrr/commit/9ec4687)
## [v0.14.0] - 2019-09-28
### Features
- **UI:** made dropdowns non-editable [37f5547](https://gitlab.com/Earthnuker/ed_lrr/commit/37f5547)
### Miscellaneous
- Alsways compile in release mode [e9bcd3e](https://gitlab.com/Earthnuker/ed_lrr/commit/e9bcd3e)
## [v0.13.0] - 2019-09-28
### Features
- **config:** finish integrating new configuration system [a8d6a32](https://gitlab.com/Earthnuker/ed_lrr/commit/a8d6a32)
## [v0.12.0] - 2019-09-28
### Features
- **Router:** finish implementing route computation progress display [93f655c](https://gitlab.com/Earthnuker/ed_lrr/commit/93f655c)
### Miscellaneous
- Add VSCode workspace config to gitignore [a91fa73](https://gitlab.com/Earthnuker/ed_lrr/commit/a91fa73)
- formatting [f78ec66](https://gitlab.com/Earthnuker/ed_lrr/commit/f78ec66)
- **CI:** rename main executable before building installer [dc0e3fc](https://gitlab.com/Earthnuker/ed_lrr/commit/dc0e3fc)
## [v0.11.0] - 2019-09-28
### Features
- **GUI:** Integrate route computation Job [f4e6bd3](https://gitlab.com/Earthnuker/ed_lrr/commit/f4e6bd3)
## [v0.10.0] - 2019-09-28
### Features
- **GUI:** Integrate new config system [22ca2d2](https://gitlab.com/Earthnuker/ed_lrr/commit/22ca2d2)
### Miscellaneous
- re-export config from main GUI module [0d89106](https://gitlab.com/Earthnuker/ed_lrr/commit/0d89106)
## [v0.9.0] - 2019-09-28
### Features
- **cli:** Add config editor [8b0b56f](https://gitlab.com/Earthnuker/ed_lrr/commit/8b0b56f)
## [v0.8.0] - 2019-09-28
### Features
- **router:** Implement route computation job with progress dualog [2c000da](https://gitlab.com/Earthnuker/ed_lrr/commit/2c000da)
### Miscellaneous
- **setup.py:** Pull version info from git, unify scripts (one script for GUI and CLI) [a630851](https://gitlab.com/Earthnuker/ed_lrr/commit/a630851)
## [v0.7.0] - 2019-09-28
### Documentation
- Update README.md [66267e7](https://gitlab.com/Earthnuker/ed_lrr/commit/66267e7)
### Features
- **installer:** Download EDSM dumps after install [4237b30](https://gitlab.com/Earthnuker/ed_lrr/commit/4237b30)
### Miscellaneous
- Update icon generator and regenerate icon [7838480](https://gitlab.com/Earthnuker/ed_lrr/commit/7838480)
## [v0.6.0] - 2019-09-28
### Features
- **router:** Start implementing route pruning support [88a0378](https://gitlab.com/Earthnuker/ed_lrr/commit/88a0378)
## [v0.5.0] - 2019-09-28
### Features
- **config:** Update config system to use profig [b1143c3](https://gitlab.com/Earthnuker/ed_lrr/commit/b1143c3)
## [v0.4.0] - 2019-09-28
### Features
- **build system:** Remove build.py (switched to tox), add output to build_gui.py [fb3a130](https://gitlab.com/Earthnuker/ed_lrr/commit/fb3a130)
## [v0.3.0] - 2019-09-28
### Features
- **router:** Add dialog to display computed route [d498746](https://gitlab.com/Earthnuker/ed_lrr/commit/d498746)
## [v0.2.11] - 2019-09-21
### Bug Fixes
- switch inno setup version in appveyor [fe3534e](https://gitlab.com/Earthnuker/ed_lrr/commit/fe3534e)
## [v0.2.10] - 2019-09-21
### Bug Fixes
- typo in appveyor.yml [09e6f0a](https://gitlab.com/Earthnuker/ed_lrr/commit/09e6f0a)
## [v0.2.9] - 2019-09-21
### Bug Fixes
- disable confirmation for conda install [eaddb18](https://gitlab.com/Earthnuker/ed_lrr/commit/eaddb18)
## [v0.2.8] - 2019-09-21
### Bug Fixes
- add missing conda channel [6d9f1ef](https://gitlab.com/Earthnuker/ed_lrr/commit/6d9f1ef)
## [v0.2.7] - 2019-09-21
### Bug Fixes
- add missing dependencies to appveyor.yml [e8beb55](https://gitlab.com/Earthnuker/ed_lrr/commit/e8beb55)
## [v0.2.6] - 2019-09-20
### Bug Fixes
- fix nuikta call to clean build directory [fa485be](https://gitlab.com/Earthnuker/ed_lrr/commit/fa485be)
## [v0.2.5] - 2019-09-20
### Bug Fixes
- fix nuikta call to download without confirmation [11efe30](https://gitlab.com/Earthnuker/ed_lrr/commit/11efe30)
## [v0.2.4] - 2019-09-20
### Bug Fixes
- fixed appveyor.yml [59390fe](https://gitlab.com/Earthnuker/ed_lrr/commit/59390fe)
## [v0.2.3] - 2019-09-20
### Bug Fixes
- fixed tox.ini [6bb7e1e](https://gitlab.com/Earthnuker/ed_lrr/commit/6bb7e1e)
### Documentation
- small wording change [3779911](https://gitlab.com/Earthnuker/ed_lrr/commit/3779911)
## [v0.2.2] - 2019-08-31
### Bug Fixes
- **setup:** fix setup script to include subdirectories [4a392d9](https://gitlab.com/Earthnuker/ed_lrr/commit/4a392d9)
### Documentation
- Insert page break after table of contents [f027e02](https://gitlab.com/Earthnuker/ed_lrr/commit/f027e02)
- Update documentation to include basic description [714741a](https://gitlab.com/Earthnuker/ed_lrr/commit/714741a)
- Rename `doc` folder to `docs`, update outline [fb54bda](https://gitlab.com/Earthnuker/ed_lrr/commit/fb54bda)
- Add skeleton for documentation [dbc6f35](https://gitlab.com/Earthnuker/ed_lrr/commit/dbc6f35)
### Miscellaneous
- Update changelog template to make conversion to PDF easier [87550a9](https://gitlab.com/Earthnuker/ed_lrr/commit/87550a9)
- **formatting:** ran `cargo fmt` and `cargo clippy`, fixed all warnings [fb3f79b](https://gitlab.com/Earthnuker/ed_lrr/commit/fb3f79b)
## [v0.2.1] - 2019-08-05
### Bug Fixes
- **router:** Fixed some syntax errors created by botched merge [4b14643](https://gitlab.com/Earthnuker/ed_lrr/commit/4b14643)
## [v0.2.0] - 2019-08-05
### Features
- **GUI:** Implement route plotting and fuzzy search [c290d5e](https://gitlab.com/Earthnuker/ed_lrr/commit/c290d5e)
## [v0.1.0] - 2019-07-22
### Features
- **GUI:** Add Download functionality, update Rust code, update Python code [ec3972b](https://gitlab.com/Earthnuker/ed_lrr/commit/ec3972b)
## v0.0.0 - 2019-07-15
[Unreleased]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.24.0...HEAD
[v0.24.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.23.0...v0.24.0
[v0.23.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.22.0...v0.23.0
[v0.22.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.21.0...v0.22.0
[v0.21.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.20.0...v0.21.0
[v0.20.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.19.1...v0.20.0
[v0.19.1]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.19.0...v0.19.1
[v0.19.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.18.0...v0.19.0
[v0.18.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.17.0...v0.18.0
[v0.17.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.16.0...v0.17.0
[v0.16.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.15.0...v0.16.0
[v0.15.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.14.0...v0.15.0
[v0.14.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.13.0...v0.14.0
[v0.13.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.12.0...v0.13.0
[v0.12.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.11.0...v0.12.0
[v0.11.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.10.0...v0.11.0
[v0.10.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.9.0...v0.10.0
[v0.9.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.8.0...v0.9.0
[v0.8.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.7.0...v0.8.0
[v0.7.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.6.0...v0.7.0
[v0.6.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.5.0...v0.6.0
[v0.5.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.4.0...v0.5.0
[v0.4.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.3.0...v0.4.0
[v0.3.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.2.11...v0.3.0
[v0.2.11]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.2.10...v0.2.11
[v0.2.10]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.2.9...v0.2.10
[v0.2.9]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.2.8...v0.2.9
[v0.2.8]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.2.7...v0.2.8
[v0.2.7]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.2.6...v0.2.7
[v0.2.6]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.2.5...v0.2.6
[v0.2.5]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.2.4...v0.2.5
[v0.2.4]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.2.3...v0.2.4
[v0.2.3]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.2.2...v0.2.3
[v0.2.2]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.2.1...v0.2.2
[v0.2.1]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.2.0...v0.2.1
[v0.2.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.1.0...v0.2.0
[v0.1.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.0.0...v0.1.0

825
Cargo.lock generated
View File

@ -1,825 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "aho-corasick"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ansi_term"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "atty"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "autocfg"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bincode"
version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bitflags"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "block-buffer"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "block-padding"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bstr"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-automata 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "byte-tools"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "byteorder"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cfg-if"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "clap"
version = "2.33.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "clicolors-control"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cloudabi"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "console"
version = "0.7.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"clicolors-control 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"encode_unicode 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "csv"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bstr 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "csv-core"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "digest"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ed_lrr"
version = "0.1.0"
dependencies = [
"bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"csv 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"humantime 1.2.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)",
"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_derive 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)",
"structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "either"
version = "1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "encode_unicode"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "fnv"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "fuchsia-cprng"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "generic-array"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "heck"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "humantime"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "indicatif"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"console 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"number_prefix 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "itertools"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "itoa"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "keccak"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lazy_static"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.2.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lock_api"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "memchr"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-traits"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "number_prefix"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "numtoa"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "opaque-debug"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "parking_lot"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lock_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "parking_lot_core"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "pdqselect"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "permutohedron"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "proc-macro2"
version = "0.4.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "quick-error"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "quote"
version = "0.6.12"
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)",
]
[[package]]
name = "rand"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_chacha"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_core"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_core"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rand_hc"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_isaac"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_jitter"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_os"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_pcg"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_xorshift"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rdrand"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "redox_syscall"
version = "0.1.54"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "redox_termios"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex"
version = "1.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"utf8-ranges 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex-automata"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex-syntax"
version = "0.6.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rstar"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"pdqselect 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc_version"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ryu"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "ryu"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "scopeguard"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "semver"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "semver-parser"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde"
version = "1.0.94"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde_derive 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_derive"
version = "1.0.94"
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 = "serde_json"
version = "1.0.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "sha3"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
"byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "smallvec"
version = "0.6.10"
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 = "structopt"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
"structopt-derive 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "structopt-derive"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"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 = "syn"
version = "0.15.39"
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)",
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "termion"
version = "1.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "termios"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "textwrap"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "thread_local"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "typenum"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "ucd-util"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-segmentation"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-width"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-xid"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "utf8-ranges"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "vec_map"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c"
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
"checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf"
"checksum bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9f04a5e50dc80b3d5d35320889053637d15011aed5e66b66b37ae798c65da6f7"
"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd"
"checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"
"checksum block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4dc3af3ee2e12f3e5d224e5e1e3d73668abbeb69e566d361f7d5563a4fdf09"
"checksum bstr 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc0572e02f76cb335f309b19e0a0d585b4f62788f7d26de2a13a836a637385f"
"checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
"checksum clicolors-control 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "73abfd4c73d003a674ce5d2933fca6ce6c42480ea84a5ffe0a2dc39ed56300f9"
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
"checksum console 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8ca57c2c14b8a2bf3105bc9d15574aad80babf6a9c44b1058034cdf8bd169628"
"checksum csv 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a54cd62557f353f140b42305fb4efcff2ae08e32fbabaf5b0929423000febb63"
"checksum csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9b5cadb6b25c77aeff80ba701712494213f4a8418fcda2ee11b6560c3ad0bf4c"
"checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c"
"checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b"
"checksum encode_unicode 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "90b2c9496c001e8cb61827acdefad780795c42264c137744cae6f7d9e3450abd"
"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
"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 heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
"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 itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358"
"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
"checksum keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7"
"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
"checksum libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "6281b86796ba5e4366000be6e9e18bf35580adf9e63fbe2294aadb587613a319"
"checksum lock_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed946d4529956a20f2d63ebe1b69996d5a2137c91913fe3ebbeff957f5bca7ff"
"checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39"
"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32"
"checksum number_prefix 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dbf9993e59c894e3c08aa1c2712914e9e6bf1fcbfc6bef283e2183df345a4fee"
"checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
"checksum opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "93f5bb2e8e8dec81642920ccff6b61f1eb94fa3020c5a325c9851ff604152409"
"checksum parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fa7767817701cce701d5585b9c4db3cdd02086398322c1d7e8bf5094a96a2ce7"
"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 permutohedron 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b687ff7b5da449d39e418ad391e5e08da53ec334903ddbb921db208908fc372c"
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
"checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db"
"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0"
"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
"checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b"
"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"
"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
"checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252"
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
"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-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 rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
"checksum ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "b96a9549dc8d48f2c283938303c4b5a77aa29bfbc5b54b084fb1630408899a8f"
"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 semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
"checksum serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)" = "076a696fdea89c19d3baed462576b8f6d663064414b5c793642da8dfeb99475b"
"checksum serde_derive 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)" = "ef45eb79d6463b22f5f9e16d283798b7c0175ba6050bc25c1a946c122727fe7b"
"checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d"
"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 strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
"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"
"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 termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72b620c5ea021d75a735c943269bb07d30c9b77d6ac6b236bc8b5c496ef05625"
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"
"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86"
"checksum unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1967f4cdfc355b37fd76d2a954fb2ed3871034eb4f26d60537d88795cfc332a9"
"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 utf8-ranges 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9d50aa7650df78abf942826607c62468ce18d9019673d4a2ebe1865dbb96ffde"
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
"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-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

View File

@ -1,26 +0,0 @@
[package]
name = "ed_lrr"
version = "0.1.0"
authors = ["Daniel Seiller <earthnuker@gmail.com>"]
edition = "2018"
repository = "https://gitlab.com/Earthnuker/ed_lrr.git"
license = "WTFPL"
[profile.release]
# debug=true
[dependencies]
csv = "1.1.0"
serde = "1.0.94"
serde_derive = "1.0.94"
rstar = {version="0.4.0",features=["serde"]}
humantime = "1.2.0"
structopt = "0.2.18"
permutohedron = "0.2.4"
serde_json = "1.0.39"
indicatif = "0.11.0"
fnv = "1.0.6"
bincode = "1.1.4"
sha3 = "0.8.2"
byteorder = "1.3.2"

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 Daniel Seiller
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

3
MANIFEST.in Normal file
View File

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

102
README.md
View File

@ -1,20 +1,82 @@
# Elite: Dangerous Long Range Router (Rust Version)
## Usage:
1. download `bodies.json` and `systemsWithCoordinates.json` from https://www.edsm.net/en/nightly-dumps/ and place them in the `dumps` folder
2. run `cargo +nightly install --path .` or `cargo +nightly install --git https://gitlab.com/Earthnuker/ed_lrr.git`
3. run `ed_lrr_pp --bodies dumps/bodies.json --systems dumps/systemsWithCoordinates.json`
- Alternatively run `process.py` in the `dumps` folder
4. run `ed_lrr --help`
## Dependencies
- Working nightly Rust Compiler (tested with `rustc 1.37.0-nightly (5d8f59f4b 2019-06-04)`)
- ~8GB of free RAM
- Optional:
- Python 3.7
- Pandas
- uJSON
# Elite: Dangerous Long-range router
## Features
- Three different routing algorithms:
- **Breadth-first search:**, always finds the shortest route but is quite slow
- **A-Star:** has an adjustable tradeoff between speed and quality
- **Greedy search:** always picks the next reachable star that's closest to the destination, very fast but very poor quality routes
- Nice GUI! (made with PyQt5)
- Two themes! (Dark and Light)
- Uses data from (EDSM)[https://edsm.net/] for star data
- Only routes through scoopable systems, no more running out of fuel! (assuming you have a fuel scoop)
- Precomputing of BFS routing graphs for near-instant routing from your home system to any destination!
- Routing code written in Rust, so it's quite speedy!
- Export routes as HTML, JSON, CSV and SVG (WIP!)
- Automagically copy next jump destination into system clipboard (works by monitoring the player journal file)
# Installation
## Prerequisites
- Python:
- conda (miniconda/anaconda)
- tox (`conda install tox`)
- Inno Setup Compiler
- Download from [here](http://www.jrsoftware.org/isdl.php)
- or install via [scoop](https://scoop.sh/) `scoop install inno-setup`)
- Visual Studio 2019
- nightly rust compiler (`x86_64-pc-windows-msvc`)
## Building an installer
(Assuming `conda` is in your `PATH`)
1. Start a Visual Studio 2019 x64 command prompt
2. Run `tox`
3. Grab the installer from `installer/Output/`
## Manual installation
(Assuming `conda` is in your `PATH`)
1. Start a Visual Studio 2019 x64 command prompt
2. Run the following commands:
```
conda install pycrypto nuitka
pip install PyQt5 setuptools_rust
python build_gui.py
pip install .
```
then you can run `ed_lrr -h` from your command prompt to get help
# To do
## Router
- Caching wrapper for System
- Only fetch position once when building Spatial-Tree
- Fetch data on demand
## GUI
- Implement estimate time to completion display for route computation and preprocessing
- Export route as:
- JSON
- HTML (WIP)
- CSV
- SVG
## Installer
- Update PATH from installer
## Preprocessing
- Build index over `systemsWithCoordinates.json` instead of loading it into RAM (reuse modified `LineCache` from `router.rs`)
## Misc
- Luigi based Task queue for distributed routing

43
appveyor.yml Normal file
View File

@ -0,0 +1,43 @@
image: Visual Studio 2019
platform: x64
version: 0.1.{build}
branches:
only:
- pyqt_gui
environment:
VCVARS: C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat
VCVARSARG: x64
MINICONDA: C:\Miniconda3-x64
INNO: C:\Program Files (x86)\Inno Setup 6
build: off
artifacts:
- path: exe\__main__.dist\
name: ED_LRR
type: zip
- path: installer\Output\*.exe
name: Setup
type: file
install:
- set PATH=%MINICONDA%\\Library\\bin;%MINICONDA%\\Scripts;%USERPROFILE%\\.cargo\\bin;%PATH%
- set PATH=%INNO%;%PATH%
- appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe
- rustup-init -y --default-toolchain nightly --default-host x86_64-pc-windows-msvc
- if defined VCVARS call "%VCVARS%" %VCVARSARG%
- conda activate
- conda update -y -n base -c defaults conda
- conda install -y -c conda-forge pycrypto nuitka
- pip install PyQt5 setuptools_rust
test_script:
- python build_gui.py
- pip install .[dev]
- python -m nuitka --plugin-enable=multiprocessing --remove-output --plugin-enable=qt-plugins --standalone --assume-yes-for-downloads --follow-imports --output-dir=exe ed_lrr_gui\__main__.py
- rename exe\__main__.dist\__main__.exe ED_LRR.exe
- cd installer
- iscc /QP ED_LRR.iss

16
build_gui.py Normal file
View File

@ -0,0 +1,16 @@
import subprocess as SP
from glob import glob
import os
ui_path = os.path.dirname(os.path.abspath(__file__))
for root, folders, files in os.walk(ui_path):
if ".history" in folders:
folders.remove(".history")
for file in files:
file = os.path.join(root, file)
outfile, ext = os.path.splitext(file)
if ext == ".ui":
outfile = outfile + ".py"
print(file, "->", outfile)
SP.check_call(["pyuic5", "--from-imports", "-o", outfile, file])

11
docs/.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,11 @@
{
"spellright.language": [
"de",
"en"
],
"spellright.documentTypes": [
"markdown",
"latex",
"plaintext"
]
}

48
docs/Makefile Normal file
View File

@ -0,0 +1,48 @@
MD = $(wildcard src/*.md)
DOTS = $(wildcard src/*.dot)
ASYS = $(wildcard src/*.asy)
PYS = $(wildcard src/img_*.py)
PDFS = $(MD:src/%.md=out/%.pdf)
IMG_PDFS = $(ASYS:src/%.asy=img/%.pdf) $(PYS:src/img_%.py=img/%.pdf) $(DOTS:src/%.dot=img/%.pdf)
IMGS = $(IMG_PDFS)
TEMPLATE = eisvogel
PDF_ENGINE = xelatex
PANDOC = pandoc
PANDOC_OPTIONS = -F panflute -F pandoc-citeproc --pdf-engine=$(PDF_ENGINE) --template $(TEMPLATE) -N --standalone --listings
GRAPHVIZ = dot
GRAPHVIZ_OPTIONS = -Tpdf
ASY = asy
ASY_OPTIONS = -noV -f pdf
PYTHON = python
PYTHON_OPTIONS =
mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
current_dir := $(notdir $(patsubst %/,%,$(dir $(mkfile_path))))
.PHONY: clean all default
all: $(PDFS)
default: all
out/%.pdf: src/%.md $(IMGS) Makefile
$(PANDOC) $(PANDOC_OPTIONS) -o $@ $<
img/%.pdf: src/%.dot
$(GRAPHVIZ) $(GRAPHVIZ_OPTIONS) -o $@ $<
img/%.pdf: src/img_%.py
$(PYTHON) $(PYTHON_OPTIONS) $< $@
img/%.pdf: src/%.asy
$(ASY) $(ASY_OPTIONS) -o $@ $<
watch:
watchexec -w src -w data -w filters -w Makefile make all
clean:
-rm $(PDFS) $(IMGS)

157
docs/filters/multifilter.py Normal file
View File

@ -0,0 +1,157 @@
import contextlib
import csv
import datetime
import hashlib
import io
import os
import re
import subprocess as SP
import sys
import tempfile
from functools import partial
import panflute as pf
from dateutil.parser import parse as dateparse
from jinja2 import Environment, PackageLoader, Template, select_autoescape
from panflute import *
def remove_pound(elem, doc):
if type(elem) == Str:
return Str(elem.text.lstrip("#"))
def fix_color(elem, doc):
if type(elem) == MetaMap:
for k in elem.content:
if k.endswith("-color"):
elem[k] = elem[k].walk(remove_pound)
def update_date(elem, doc):
if type(elem) == MetaMap:
datefmt = doc.get_metadata("datefmt", "%Y-%m-%d")
today = datetime.date.today().strftime(datefmt)
date = dateparse(doc.get_metadata("date", today)).date()
elem["date"] = MetaInlines(Str(date.strftime(datefmt)))
return elem
def csv_table(elem, doc):
if type(elem) == Para and len(elem.content) == 1 and type(elem.content[0]) == Image:
elem = elem.content[0]
ext = os.path.splitext(elem.url)[1][1:]
if ext == "csv":
caption = elem.content
has_header = elem.attributes.get("has-header", "false").lower() == "true"
with open(elem.url) as f:
reader = csv.reader(f)
body = []
for row in reader:
cells = [TableCell(Plain(Str(x))) for x in row]
body.append(TableRow(*cells))
header = body.pop(0) if has_header else None
ret = Table(*body, header=header, caption=caption)
return ret
def code_refs(elem, doc):
if type(elem) == Cite:
label = elem.content[0]
if type(label) == Str:
label = label.text
filename = re.findall(r"^\[@lst:(.*)\]$", label) or [None]
if filename[0] in doc.inc_files:
return [
RawInline(
"\\hyperref[{}]{{{}}}".format(filename[0], filename[0]),
format="tex",
)
]
def include_code(elem, doc):
if type(elem) == CodeBlock:
if "include" in elem.attributes:
filepath = elem.attributes.pop("include")
filename = os.path.split(filepath)[-1]
try:
elem.text += elem.text + open(filepath, encoding="utf-8").read()
elem.attributes["caption"] = filename
doc.inc_files.append(filename)
except Exception as e:
elem.text += "Error: {}".format(e)
return [RawBlock("\\label{{{}}}".format(filename), format="tex"), elem]
def py_eval(options, data, element, doc):
out_buffer = io.StringIO()
with contextlib.redirect_stdout(out_buffer):
exec(data, doc.pyenv)
out_buffer.seek(0)
return convert_text(out_buffer.read())
def jinja_py_filt(doc, file):
env = {}
code = open(file, encoding="utf-8").read()
exec(code, env)
return env["main"](doc)
def prepare(doc):
doc.inc_files = []
doc.env = Environment()
doc.pyenv = {}
filters = {"py": partial(jinja_py_filt, doc)}
doc.env.filters.update(filters)
def process_templates(elem, doc):
if type(elem) == CodeBlock:
if elem.classes == ["@"]:
args = {"meta": doc.get_metadata()}
return convert_text(doc.env.from_string(elem.text).render(args))
def yaml_filt(elem, doc):
tags = {"eval": py_eval}
return yaml_filter(elem, doc, tags=tags, strict_yaml=True)
def checkboxes(elem, doc):
if type(elem) in [Para, Plain]:
val = re.findall(r"^\[([xX]|\ )\] (.*)$", stringify(elem))
if val:
val = val[0][0].lower() == "x"
else:
return elem
marker = {
True: RawInline("$\\boxtimes$", format="latex"),
False: RawInline("$\\square$", format="latex"),
}[val]
cont = []
if val:
cont += elem.content[2:]
else:
cont += elem.content[4:]
return Plain(marker, Space, *cont)
return elem
def main(doc=None):
f = [
process_templates,
update_date,
csv_table,
include_code,
fix_color,
code_refs,
yaml_filt,
checkboxes,
]
return run_filters(f, prepare=prepare, doc=doc)
if __name__ == "__main__":
main()

92
docs/src/ed-lrr.md Normal file
View File

@ -0,0 +1,92 @@
---
# Metadata
title: ED_LRR
author:
- Daniel Seiller <earthnuker@gmail.com>
subtitle: 'Elite Dangerous: Long-Range Router'
# Formating
toc: true
lang: en
colorlinks: true
papersize: a4
numbersections: true
#Panflute options
panflute-filters: [multifilter]
panflute-path: 'filters'
#Template options
titlepage: true
toc-own-page: false
---
\pagebreak
# Implementation
## `stars.csv` format
### Columns
| Name | Content |
| --------- | ------------------------------------------------------------ |
| id | unique ID-Number (not equal to id or id64, just a sequential number) |
| star_type | Type of Star |
| system | Name of System |
| body | Name of Star |
| mult | Jump Range Multiplier (1.5 for White Dwarfs, 4.0 for Neutron Stars) |
| distance | Distance from arrival in Ls |
| x,y,z | Position in Galactic Coordinates with Sol at (0,0,0) |
## `stars.idx` format
`bincode` serialized data:
- **[u64]**: List of byte offset for records (entry 0=first recod, entry 1= second record, etc)
## Routing Algorithms
### Breadth-First Search (BFS)
Standard Breadth-First Search, always finds the shortest route
### A*-Search
Modified A*-Search with adjustable "greediness". Priority Queue weighted by $\text{number of jumps from start system} + (\text{estimated number of jumps to target system} * \text{greediness})$
A greediness of 0 is equivalent to BFS and a greediness of $\infty$ is equivalent to Greedy-Search
### Greedy-Search
Priority Queue weighted by minimum distance to target, prefers systems with high multiplier (Neutron Stars and White Dwarfs)
## Optimizations
### Ellipse elimination
Only consider systems within an ellipsoid with source and destination as the foci, the width of the ellipsoid is adjustable
## Routing Graphs
### File format
`bincode` serialized data:
- *bool* **primary**: flag to indicate that graph only includes primary stars
- *f32* **range**: jump range for routing graph
- *[u8]* **file_hash**: sha3 hash of `stars.csv` from which graph was generated
- *String* **path**: path to `stars.csv` from which graph was generated
- *FnvHashMap* **graph**: Hashmap mapping systems to the systems from which they can be rached, traversed from destination system backwards to source to reconstruct route
# Usage
<!--
TODO: Add screenshots
-->
## Preprocessing Data
## Plotting a Route
# [Changelog](https://gitlab.com/Earthnuker/ed_lrr/blob/pyqt_gui/CHANGELOG.md)

65
docs/src/img_out.py Normal file
View File

@ -0,0 +1,65 @@
import heapq
import sys
import numpy as np
import pylab as PL
from scipy.spatial.ckdtree import cKDTree
exit()
def vec(a, b):
return b - a
def bfs(points):
return
def in_ellipse(p, f1, f2, r, offset=0):
df = ((f1 - f2) ** 2).sum(0) ** 0.5
d_f1 = ((p - f1) ** 2).sum(1) ** 0.5
d_f2 = ((p - f2) ** 2).sum(1) ** 0.5
return (d_f1 + d_f2) < (df * (1 + r))
num_points = 100000
p_orig = np.random.normal(0, 10, size=(num_points, 2))
tree = cKDTree(p_orig)
f1 = np.array([0, -30])
f2 = -f1 # np.random.normal(0, 20, (3,))
# r = 2 ** ((n / cnt) - cnt)
mask = in_ellipse(p_orig, f1, f2, 0.1)
p = p_orig[mask]
p_orig = p_orig[~mask]
colors = np.random.random(p.shape[0])
fig = PL.gcf()
PL.scatter(
p_orig[:, 0],
p_orig[:, 1],
marker=".",
s=0.2,
edgecolor="None",
c=[(0.0, 0.0, 0.0)],
alpha=0.75,
rasterized=True,
)
PL.scatter(
p[:, 0], p[:, 1], marker="s", s=0.2, edgecolor="None", c=colors, rasterized=True
)
PL.plot(f1[0], f1[1], "r.", label="Source")
PL.plot(f2[0], f2[1], "g.", label="Destination")
max_v = max(p_orig[:, 0].max(), p_orig[:, 1].max(), f1[0], f1[1], f2[0], f2[1]) + 2
min_v = min(p_orig[:, 0].min(), p_orig[:, 1].min(), f1[0], f1[1], f2[0], f2[1]) - 2
PL.xlim(min_v, max_v)
PL.ylim(min_v, max_v)
PL.legend()
PL.savefig(sys.argv[1], dpi=1200)

View File

@ -1,180 +0,0 @@
import ujson as json
from tqdm import tqdm
from pprint import pprint
import itertools as ITT
import os
import sys
import csv
import sqlite3
import pandas as pd
from urllib.parse import urljoin
def is_scoopable(entry):
first = entry.type.split()[0]
return first == "Neutron" or first == "White" or first in "KGBFOAM"
def get_mult(name):
try:
first = name.split()[0]
except:
return 1
if first == "Neutron":
return 4
if first == "White":
return 1.5
return 1
def dict_factory(cursor, row):
d = {}
for idx, col in enumerate(cursor.description):
d[col[0]] = row[idx]
return d
def blocks(files, size=65536):
while True:
b = files.read(size)
if not b:
break
yield b
def getlines(f, fn, show_progbar=False):
f.seek(0, 2)
size = f.tell()
f.seek(0)
progbar = tqdm(
desc="Processing " + fn,
total=size,
unit="b",
unit_scale=True,
unit_divisor=1024,
ascii=True,
leave=True,
disable=(not show_progbar),
)
buffer = []
for block in blocks(f):
progbar.n = f.tell()
progbar.update(0)
if buffer:
buffer += (buffer.pop(0) + block).splitlines(keepends=True)
else:
buffer += block.splitlines(keepends=True)
while buffer and buffer[0].endswith("\n"):
try:
yield json.loads(buffer.pop(0).strip().rstrip(","))
except ValueError:
pass
while buffer:
try:
yield json.loads(buffer.pop(0).strip().rstrip(","))
except ValueError:
pass
def process_file(fn, show_progbar=False):
with open(fn, "r") as f:
for line in tqdm(
getlines(f, fn, show_progbar),
desc=fn,
unit=" lines",
unit_scale=True,
ascii=True,
leave=True,
disable=(not show_progbar),
):
yield line
if not (
os.path.isfile("bodies.json") and os.path.isfile("systemsWithCoordinates.json")
):
exit(
"Please download bodies.json and systemsWithCoordinates.json from https://www.edsm.net/en/nightly-dumps/"
)
if not os.path.isfile("stars.jl"):
print("Filtering for Stars")
with open("stars.jl", "w") as neut:
for body in process_file("bodies.json", True):
T = body.get("type") or ""
if "Star" in T:
neut.write(json.dumps(body) + "\n")
def load_systems(load=False):
load = not os.path.isfile("systems.db")
cache = sqlite3.connect("systems.db")
cache.row_factory = dict_factory
c = cache.cursor()
if load:
print("Caching Systems")
c.execute("DROP TABLE IF EXISTS systems")
c.execute(
"CREATE TABLE systems (id64 int primary key, name text, x real, y real, z real)"
)
cache.commit()
recs = []
for system in process_file("systemsWithCoordinates.json", True):
rec = [
system["id64"],
system["name"],
system["coords"]["x"],
system["coords"]["y"],
system["coords"]["z"],
]
recs.append(rec)
if len(recs) % 1024 * 1024 == 0:
c.executemany("INSERT INTO systems VALUES (?,?,?,?,?)", recs)
recs.clear()
c.executemany("INSERT INTO systems VALUES (?,?,?,?,?)", recs)
cache.commit()
return cache, c
if not os.path.isfile("stars.csv"):
cache, cur = load_systems()
rows = []
with open("stars.csv", "w", newline="") as sys_csv:
csv_writer = csv.writer(sys_csv, dialect="excel")
for neut in process_file("stars.jl", True):
cur.execute(
"SELECT * FROM systems WHERE id64==?", (neut.get("systemId64"),)
)
system = cur.fetchone()
if not system:
continue
row = [
neut["systemId64"],
neut["subType"],
neut["name"],
get_mult(neut["subType"]),
system["x"],
system["y"],
system["z"],
]
rows.append(row)
if len(rows) > 1024:
csv_writer.writerows(rows)
rows.clear()
csv_writer.writerows(rows)
print()
cache.close()
if not os.path.isfile("stars.csv"):
tqdm.pandas(ascii=True, leave=True)
print("Loading data...")
data = pd.read_csv(
"stars.csv",
encoding="utf-8",
names=["id", "type", "name", "mult", "x", "y", "z"],
)
print("Cleaning data...")
data.type.fillna("Unknown", inplace=True)
data.drop_duplicates("id", inplace=True)
print("Writing CSV...")
data.to_csv("stars.csv", header=False, index=False)

View File

@ -1,2 +0,0 @@
https://www.edsm.net/dump/systemsWithCoordinates.json
https://www.edsm.net/dump/bodies.json

5
ed_lrr_gui/__init__.py Normal file
View File

@ -0,0 +1,5 @@
from _ed_lrr import *
from .preprocess import Preprocessor
from .router import Router
from .config import cfg

403
ed_lrr_gui/__main__.py Normal file
View File

@ -0,0 +1,403 @@
import sys
import multiprocessing as MP
import queue
import ctypes
import os
from datetime import datetime
from math import floor
import click
from tqdm import tqdm
from click_default_group import DefaultGroup
import requests as RQ
from urllib.parse import urljoin
from ed_lrr_gui import Router, Preprocessor, cfg
from _ed_lrr import find_sys
CONTEXT_SETTINGS = dict(help_option_names=["-h", "--help"])
stars_path = os.path.join(cfg["folders.data_dir"], "stars.csv")
for folder in cfg["history.stars_csv_path"]:
file = os.path.join(folder, "stars.csv")
if os.path.isfile(file):
stars_path = file
break
systems_path = os.path.join(cfg["folders.data_dir"], "systemsWithCoordinates.json")
for file in cfg["history.systems_path"]:
if os.path.isfile(file):
systems_path = file
break
bodies_path = os.path.join(cfg["folders.data_dir"], "bodies.json")
for file in cfg["history.bodies_path"][::-1]:
if os.path.isfile(file):
bodies_path = file
break
@click.group(invoke_without_command=True, context_settings=CONTEXT_SETTINGS)
@click.pass_context
@click.version_option()
def main(ctx):
"Elite: Dangerous long range router, command line interface"
MP.freeze_support()
if ctx.invoked_subcommand != "config":
os.makedirs(cfg["folders.data_dir"], exist_ok=True)
if ctx.invoked_subcommand is None:
ctx.invoke(gui)
return
return
@main.command()
@click.argument("option", default=None, required=False)
@click.argument("value", default=None, required=False)
def config(option, value):
"""Change configuration
If "key" and "value" are both omitted the current configuration is printed
"""
def print_config(key):
default = cfg.section(key).default()
comment = cfg.section(key).comment
value = cfg[key]
is_default = value == default
if (
isinstance(value, list)
and all(isinstance(element, str) for element in value)
and len(value) != 0
):
value = "[{}]".format(", ".join(map("'{}'".format, value)))
key = click.style("{}".format(key), fg="cyan")
value = click.style("{}".format(value), fg="green")
default = click.style("{}".format(default), fg="blue")
comment = click.style("{}".format(comment), fg="yellow")
if is_default:
print("{}: {} # {}".format(key, default, comment))
else:
print("{}: {} (default: {}) # {}".format(key, value, default, comment))
if option is None and value is None:
click.secho("Config path: {}".format(cfg.sources[0]), bold=True)
print()
for key in cfg:
print_config(key)
return
if value is None:
if option in cfg:
print_config(option)
else:
print("Invalid option:", option)
return
cfg[option] = value
cfg.sync()
return
@main.command()
def explore():
"Open file manager in data folder"
click.launch(cfg["folders.data_dir"], locate=True)
@main.command()
@click.option("--debug", help="Debug print", is_flag=True)
def gui(debug):
"Run the ED LRR GUI (default)"
import ed_lrr_gui.gui as ED_LRR_GUI
if (not debug) and os.name == "nt":
ctypes.windll.kernel32.FreeConsole()
sys.stdin = open("NUL", "rt")
sys.stdout = open("NUL", "wt")
sys.stderr = open("NUL", "wt")
sys.exit(ED_LRR_GUI.main())
@main.command()
@click.option(
"--url",
"-u",
help="Base URL",
default="https://www.edsm.net/dump/",
show_default=True,
)
@click.option(
"--folder",
"-f",
help="Target folder for downloads",
default=cfg["folders.data_dir"],
type=click.Path(exists=True, dir_okay=True, file_okay=False),
show_default=True,
)
def download(url, folder):
"Download EDSM dumps"
os.makedirs(folder, exist_ok=True)
for file_name in ["systemsWithCoordinates.json", "bodies.json"]:
download_url = urljoin(url, file_name)
download_path = os.path.join(folder, file_name)
if os.path.isfile(download_path):
try:
if not click.confirm(
"{} already exissts, overwrite?".format(file_name)
):
continue
except click.Abort:
exit("Canceled!")
size = RQ.head(download_url, headers={"Accept-Encoding": "None"})
size.raise_for_status()
size = int(size.headers.get("Content-Length", 0))
with tqdm(
total=size,
desc="{}".format(file_name),
unit="b",
unit_divisor=1024,
unit_scale=True,
ascii=True,
) as pbar:
with open(download_path, "wb") as of:
resp = RQ.get(
download_url, stream=True, headers={"Accept-Encoding": "gzip"}
)
for chunk in resp.iter_content(1024 * 1024):
of.write(chunk)
pbar.update(len(chunk))
click.pause()
@main.command()
@click.option(
"--systems",
"-s",
default=systems_path,
metavar="<path>",
help="Path to stars.csv",
type=click.Path(exists=True, dir_okay=False),
show_default=True,
)
@click.option(
"--bodies",
"-b",
default=bodies_path,
metavar="<path>",
help="Path to bodies.json",
type=click.Path(exists=True, dir_okay=False),
show_default=True,
)
@click.option(
"--output",
"-o",
default=stars_path,
metavar="<path>",
help="Path to stars.csv",
type=click.Path(exists=False, dir_okay=False),
show_default=True,
)
def preprocess(systems, bodies, output):
"Preprocess EDSM dumps"
with click.progressbar(
length=100, label="", show_percent=True, item_show_func=lambda v: v, width=50
) as pbar:
preproc = Preprocessor(systems, bodies, output)
preproc.start()
state = {}
pstate = {}
while not (preproc.queue.empty() and preproc.is_alive() == False):
try:
event = preproc.queue.get(True, 0.1)
state.update(event)
if state != pstate:
prc = (state["status"]["done"] / state["status"]["total"]) * 100
pbar.pos = prc
pbar.update(0)
pbar.current_item = state["status"]["message"]
pstate = state.copy()
except queue.Empty:
pass
pbar.pos = 100
pbar.update(0)
print(state.get("result"))
print("DONE!")
click.pause()
@main.command()
@click.option(
"--path",
"-i",
required=True,
metavar="<path>",
help="Path to stars.csv",
default=stars_path,
type=click.Path(exists=True, dir_okay=False),
show_default=True,
)
@click.option(
"--precomp_file",
"-pf",
metavar="<path>",
help="Precomputed routing graph to use",
type=click.Path(exists=True, dir_okay=False),
)
@click.option(
"--range",
"-r",
default=cfg["route.range"],
metavar="<float>",
help="Jump range (Ly)",
type=click.FloatRange(min=0),
show_default=True,
)
@click.option(
"--prune",
"-d",
default=(cfg["route.prune.steps"], cfg["route.prune.min_improvement"]),
metavar="<n> <m>",
help="Prune search branches",
nargs=2,
type=click.Tuple([click.IntRange(min=0), click.FloatRange(min=0)]),
show_default=True,
)
@click.option(
"--permute",
"-p",
type=click.Choice(["all", "keep_first", "keep_last", "keep_both"]),
default=None,
help="Permute hops to find shortest route",
show_default=True,
)
@click.option(
"--primary/--no-primary",
"+ps/-ps",
is_flag=True,
default=cfg["route.primary"],
help="Only route through primary stars",
show_default=True,
)
@click.option(
"--factor",
"-g",
metavar="<float>",
default=cfg["route.greediness"],
help="Greedyness factor for A-Star",
show_default=True,
)
@click.option(
"--mode",
"-m",
default=cfg["route.mode"],
help="Search mode",
type=click.Choice(["bfs", "a-star", "greedy"]),
show_default=True,
)
@click.argument("systems", nargs=-1)
def route(**kwargs):
"Compute a route"
if len(kwargs["systems"]) < 2:
exit("Need at least two systems to plot a route")
if kwargs["prune"] == (0, 0):
kwargs["prune"] = None
def to_string(state):
if state:
return "{prc_done:.2f}% [N:{depth} Q:{queue_size} D:{d_rem:.2f} Ly] {system}".format(
**state
)
keep_first, keep_last = {
"all": (False, False),
"keep_first": (True, False),
"keep_last": (False, True),
"keep_both": (True, True),
None: (False, False),
}[kwargs["permute"]]
print("Resolving systems...")
t = datetime.today()
matches = find_sys(kwargs["systems"], kwargs["path"])
kwargs["systems"] = [str(matches[key][1]["id"]) for key in kwargs["systems"]]
print("Done in", datetime.today() - t)
args = [
kwargs["systems"],
kwargs["range"],
kwargs["prune"],
kwargs["mode"],
kwargs["primary"],
kwargs["permute"] != None,
keep_first,
keep_last,
kwargs["factor"],
None,
kwargs["path"],
]
with click.progressbar(
length=100,
label="Computing route",
show_percent=False,
item_show_func=to_string,
width=50,
) as pbar:
router = Router(*args)
t = datetime.today()
router.start()
state = {}
pstate = {}
while not (router.queue.empty() and router.is_alive() == False):
try:
event = router.queue.get(True, 0.1)
state.update(event)
if state != pstate:
pbar.current_item = state.get("status")
if pbar.current_item:
pbar.pos = pbar.current_item["prc_done"]
pbar.update(0)
pstate = state.copy()
except queue.Empty:
pass
pbar.pos = 100
pbar.update(0)
for n, jump in enumerate(state.get("return", []), 1):
jump["n"] = n
if jump["body"].index(jump["system"]) == -1:
jump["where"] = "[{body}] in [{system}]".format(**jump)
else:
jump["where"] = "[{body}]".format(**jump)
if jump["distance"] > 0:
print("({n}) {where}: {star_type} ({distance} Ls)".format(**jump))
else:
print("({n}) {where}: {star_type}".format(**jump))
print("Done in", datetime.today() - t)
@main.command()
@click.option(
"--path",
"-i",
required=True,
help="Path to stars.csv",
default=stars_path,
type=click.Path(exists=True, dir_okay=False),
show_default=True,
)
@click.option(
"--range", "-r", required=True, help="Jump range (Ly)", type=click.FloatRange(min=0)
)
@click.option("--primary", "-ps", help="Only route through primary stars")
@click.option(
"--output",
"-o",
required=True,
help="Output path",
default="./stars.idx",
type=click.Path(exists=False, dir_okay=False),
show_default=True,
)
@click.argument("systems", nargs=-1)
def precompute(*args, **kwargs):
"Precompute routing graph"
print("PreComp:", args, kwargs)
if __name__ == "__main__":
main()

59
ed_lrr_gui/config.py Normal file
View File

@ -0,0 +1,59 @@
import pathlib
from collections import namedtuple
import profig
import appdirs
import os
config_dir = pathlib.Path(appdirs.user_config_dir("ED_LRR", ""))
config_dir.mkdir(parents=True, exist_ok=True)
config_file = config_dir / "config.ini"
config_file.touch()
cfg = profig.Config(str(config_file), strict=True)
cfg.init(
"history.bodies_url",
["https://www.edsm.net/dump/bodies.json"],
"path_list",
comment="history of bodies.json urls",
)
cfg.init(
"history.systems_url",
["https://www.edsm.net/dump/systemsWithCoordinates.json"],
"path_list",
comment="history of systems.json urls",
)
cfg.init(
"history.bodies_path",
[os.path.join(config_dir, "data", "bodies.json")],
"path_list",
comment="history of bodies.json download paths",
)
cfg.init(
"history.systems_path",
[os.path.join(config_dir, "data", "systemsWithCoordinates.json")],
"path_list",
comment="history of systems.json download paths",
)
cfg.init(
"history.stars_csv_path",
[os.path.join(config_dir, "data", "stars.csv")],
"path_list",
comment="history of paths for stars.csv",
)
cfg.init("route.range", 7.56, comment="jump range")
cfg.init("route.primary", False, comment="only route through primary stars")
cfg.init("route.mode", "bfs", comment="routing mode")
cfg.init(
"route.prune.min_improvement",
10.0,
comment="path needs to improve by at least (jump_range*min_improvement) in route.prune.steps",
)
cfg.init("route.prune.steps", 5, comment="number of steps before path gets pruned")
cfg.init("route.greediness", 0.5, comment="A* greediness")
cfg.init("folders.data_dir", os.path.join(config_dir, "data"), comment="Data directory")
cfg.init("GUI.theme", "dark", comment="GUI theme to use")
cfg.sync()

View File

@ -0,0 +1 @@
from .main import main

484
ed_lrr_gui/gui/ed_lrr.py Normal file
View File

@ -0,0 +1,484 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'D:\devel\rust\ed_lrr_gui\ed_lrr_gui\gui\ed_lrr.ui'
#
# Created by: PyQt5 UI code generator 5.13.1
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_ED_LRR(object):
def setupUi(self, ED_LRR):
ED_LRR.setObjectName("ED_LRR")
ED_LRR.setEnabled(True)
ED_LRR.resize(577, 500)
sizePolicy = QtWidgets.QSizePolicy(
QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed
)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(ED_LRR.sizePolicy().hasHeightForWidth())
ED_LRR.setSizePolicy(sizePolicy)
ED_LRR.setMinimumSize(QtCore.QSize(577, 500))
ED_LRR.setMaximumSize(QtCore.QSize(577, 500))
ED_LRR.setStyleSheet("")
ED_LRR.setDocumentMode(False)
ED_LRR.setTabShape(QtWidgets.QTabWidget.Rounded)
self.centralwidget = QtWidgets.QWidget(ED_LRR)
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)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName("verticalLayout")
self.tabs = QtWidgets.QTabWidget(self.centralwidget)
self.tabs.setEnabled(True)
self.tabs.setAutoFillBackground(False)
self.tabs.setTabPosition(QtWidgets.QTabWidget.North)
self.tabs.setTabShape(QtWidgets.QTabWidget.Rounded)
self.tabs.setElideMode(QtCore.Qt.ElideNone)
self.tabs.setTabsClosable(False)
self.tabs.setTabBarAutoHide(False)
self.tabs.setObjectName("tabs")
self.tab_download = QtWidgets.QWidget()
self.tab_download.setObjectName("tab_download")
self.formLayout = QtWidgets.QFormLayout(self.tab_download)
self.formLayout.setObjectName("formLayout")
self.lbl_bodies_dl = QtWidgets.QLabel(self.tab_download)
self.lbl_bodies_dl.setObjectName("lbl_bodies_dl")
self.formLayout.setWidget(
1, QtWidgets.QFormLayout.LabelRole, self.lbl_bodies_dl
)
self.lbl_systems_dl = QtWidgets.QLabel(self.tab_download)
self.lbl_systems_dl.setObjectName("lbl_systems_dl")
self.formLayout.setWidget(
3, QtWidgets.QFormLayout.LabelRole, self.lbl_systems_dl
)
self.inp_bodies_dl = QtWidgets.QComboBox(self.tab_download)
self.inp_bodies_dl.setEditable(True)
self.inp_bodies_dl.setInsertPolicy(QtWidgets.QComboBox.InsertAtTop)
self.inp_bodies_dl.setObjectName("inp_bodies_dl")
self.formLayout.setWidget(
1, QtWidgets.QFormLayout.FieldRole, self.inp_bodies_dl
)
self.inp_systems_dl = QtWidgets.QComboBox(self.tab_download)
self.inp_systems_dl.setEditable(True)
self.inp_systems_dl.setInsertPolicy(QtWidgets.QComboBox.InsertAtTop)
self.inp_systems_dl.setObjectName("inp_systems_dl")
self.formLayout.setWidget(
3, QtWidgets.QFormLayout.FieldRole, self.inp_systems_dl
)
self.gridLayout = QtWidgets.QGridLayout()
self.gridLayout.setObjectName("gridLayout")
self.inp_bodies_dest_dl = QtWidgets.QComboBox(self.tab_download)
sizePolicy = QtWidgets.QSizePolicy(
QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed
)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(
self.inp_bodies_dest_dl.sizePolicy().hasHeightForWidth()
)
self.inp_bodies_dest_dl.setSizePolicy(sizePolicy)
self.inp_bodies_dest_dl.setEditable(False)
self.inp_bodies_dest_dl.setInsertPolicy(QtWidgets.QComboBox.InsertAtTop)
self.inp_bodies_dest_dl.setObjectName("inp_bodies_dest_dl")
self.gridLayout.addWidget(self.inp_bodies_dest_dl, 0, 0, 1, 1)
self.btn_bodies_dest_browse_dl = QtWidgets.QPushButton(self.tab_download)
self.btn_bodies_dest_browse_dl.setObjectName("btn_bodies_dest_browse_dl")
self.gridLayout.addWidget(self.btn_bodies_dest_browse_dl, 0, 1, 1, 1)
self.formLayout.setLayout(2, QtWidgets.QFormLayout.FieldRole, self.gridLayout)
self.gridLayout_2 = QtWidgets.QGridLayout()
self.gridLayout_2.setObjectName("gridLayout_2")
self.btn_systems_dest_browse_dl = QtWidgets.QPushButton(self.tab_download)
self.btn_systems_dest_browse_dl.setObjectName("btn_systems_dest_browse_dl")
self.gridLayout_2.addWidget(self.btn_systems_dest_browse_dl, 0, 1, 1, 1)
self.inp_systems_dest_dl = QtWidgets.QComboBox(self.tab_download)
sizePolicy = QtWidgets.QSizePolicy(
QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed
)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(
self.inp_systems_dest_dl.sizePolicy().hasHeightForWidth()
)
self.inp_systems_dest_dl.setSizePolicy(sizePolicy)
self.inp_systems_dest_dl.setEditable(False)
self.inp_systems_dest_dl.setInsertPolicy(QtWidgets.QComboBox.InsertAtTop)
self.inp_systems_dest_dl.setObjectName("inp_systems_dest_dl")
self.gridLayout_2.addWidget(self.inp_systems_dest_dl, 0, 0, 1, 1)
self.formLayout.setLayout(4, QtWidgets.QFormLayout.FieldRole, self.gridLayout_2)
self.btn_download = QtWidgets.QPushButton(self.tab_download)
self.btn_download.setObjectName("btn_download")
self.formLayout.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.btn_download)
self.label = QtWidgets.QLabel(self.tab_download)
self.label.setObjectName("label")
self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label)
self.label_2 = QtWidgets.QLabel(self.tab_download)
self.label_2.setObjectName("label_2")
self.formLayout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.label_2)
self.tabs.addTab(self.tab_download, "")
self.tab_preprocess = QtWidgets.QWidget()
self.tab_preprocess.setObjectName("tab_preprocess")
self.formLayout_3 = QtWidgets.QFormLayout(self.tab_preprocess)
self.formLayout_3.setObjectName("formLayout_3")
self.lbl_bodies_pp = QtWidgets.QLabel(self.tab_preprocess)
self.lbl_bodies_pp.setObjectName("lbl_bodies_pp")
self.formLayout_3.setWidget(
0, QtWidgets.QFormLayout.LabelRole, self.lbl_bodies_pp
)
self.gr_bodies_pp = QtWidgets.QGridLayout()
self.gr_bodies_pp.setObjectName("gr_bodies_pp")
self.btn_bodies_browse_pp = QtWidgets.QPushButton(self.tab_preprocess)
self.btn_bodies_browse_pp.setObjectName("btn_bodies_browse_pp")
self.gr_bodies_pp.addWidget(self.btn_bodies_browse_pp, 0, 1, 1, 1)
self.inp_bodies_pp = QtWidgets.QComboBox(self.tab_preprocess)
sizePolicy = QtWidgets.QSizePolicy(
QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed
)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(
self.inp_bodies_pp.sizePolicy().hasHeightForWidth()
)
self.inp_bodies_pp.setSizePolicy(sizePolicy)
self.inp_bodies_pp.setEditable(False)
self.inp_bodies_pp.setInsertPolicy(QtWidgets.QComboBox.InsertAtTop)
self.inp_bodies_pp.setObjectName("inp_bodies_pp")
self.gr_bodies_pp.addWidget(self.inp_bodies_pp, 0, 0, 1, 1)
self.formLayout_3.setLayout(
0, QtWidgets.QFormLayout.FieldRole, self.gr_bodies_pp
)
self.lbl_systems_pp = QtWidgets.QLabel(self.tab_preprocess)
self.lbl_systems_pp.setObjectName("lbl_systems_pp")
self.formLayout_3.setWidget(
1, QtWidgets.QFormLayout.LabelRole, self.lbl_systems_pp
)
self.gr_systems_pp = QtWidgets.QGridLayout()
self.gr_systems_pp.setObjectName("gr_systems_pp")
self.btn_systems_browse_pp = QtWidgets.QPushButton(self.tab_preprocess)
self.btn_systems_browse_pp.setObjectName("btn_systems_browse_pp")
self.gr_systems_pp.addWidget(self.btn_systems_browse_pp, 0, 1, 1, 1)
self.inp_systems_pp = QtWidgets.QComboBox(self.tab_preprocess)
sizePolicy = QtWidgets.QSizePolicy(
QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed
)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(
self.inp_systems_pp.sizePolicy().hasHeightForWidth()
)
self.inp_systems_pp.setSizePolicy(sizePolicy)
self.inp_systems_pp.setEditable(False)
self.inp_systems_pp.setInsertPolicy(QtWidgets.QComboBox.InsertAtTop)
self.inp_systems_pp.setObjectName("inp_systems_pp")
self.gr_systems_pp.addWidget(self.inp_systems_pp, 0, 0, 1, 1)
self.formLayout_3.setLayout(
1, QtWidgets.QFormLayout.FieldRole, self.gr_systems_pp
)
self.lbl_out_pp = QtWidgets.QLabel(self.tab_preprocess)
self.lbl_out_pp.setObjectName("lbl_out_pp")
self.formLayout_3.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.lbl_out_pp)
self.gr_out_grid_pp = QtWidgets.QGridLayout()
self.gr_out_grid_pp.setObjectName("gr_out_grid_pp")
self.btn_out_browse_pp = QtWidgets.QPushButton(self.tab_preprocess)
sizePolicy = QtWidgets.QSizePolicy(
QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed
)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(
self.btn_out_browse_pp.sizePolicy().hasHeightForWidth()
)
self.btn_out_browse_pp.setSizePolicy(sizePolicy)
self.btn_out_browse_pp.setObjectName("btn_out_browse_pp")
self.gr_out_grid_pp.addWidget(self.btn_out_browse_pp, 0, 1, 1, 1)
self.inp_out_pp = QtWidgets.QComboBox(self.tab_preprocess)
sizePolicy = QtWidgets.QSizePolicy(
QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed
)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.inp_out_pp.sizePolicy().hasHeightForWidth())
self.inp_out_pp.setSizePolicy(sizePolicy)
self.inp_out_pp.setEditable(False)
self.inp_out_pp.setInsertPolicy(QtWidgets.QComboBox.InsertAtTop)
self.inp_out_pp.setObjectName("inp_out_pp")
self.gr_out_grid_pp.addWidget(self.inp_out_pp, 0, 0, 1, 1)
self.formLayout_3.setLayout(
2, QtWidgets.QFormLayout.FieldRole, self.gr_out_grid_pp
)
self.btn_preprocess = QtWidgets.QPushButton(self.tab_preprocess)
self.btn_preprocess.setObjectName("btn_preprocess")
self.formLayout_3.setWidget(
3, QtWidgets.QFormLayout.LabelRole, self.btn_preprocess
)
self.tabs.addTab(self.tab_preprocess, "")
self.tab_route = QtWidgets.QWidget()
self.tab_route.setObjectName("tab_route")
self.formLayout_2 = QtWidgets.QFormLayout(self.tab_route)
self.formLayout_2.setObjectName("formLayout_2")
self.lbl_sys_lst = QtWidgets.QLabel(self.tab_route)
self.lbl_sys_lst.setObjectName("lbl_sys_lst")
self.formLayout_2.setWidget(
0, QtWidgets.QFormLayout.LabelRole, self.lbl_sys_lst
)
self.gr_sys = QtWidgets.QGridLayout()
self.gr_sys.setObjectName("gr_sys")
self.btn_sys_lst_browse = QtWidgets.QPushButton(self.tab_route)
self.btn_sys_lst_browse.setObjectName("btn_sys_lst_browse")
self.gr_sys.addWidget(self.btn_sys_lst_browse, 0, 1, 1, 1)
self.inp_sys_lst = QtWidgets.QComboBox(self.tab_route)
sizePolicy = QtWidgets.QSizePolicy(
QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed
)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.inp_sys_lst.sizePolicy().hasHeightForWidth())
self.inp_sys_lst.setSizePolicy(sizePolicy)
self.inp_sys_lst.setEditable(False)
self.inp_sys_lst.setInsertPolicy(QtWidgets.QComboBox.InsertAtTop)
self.inp_sys_lst.setFrame(True)
self.inp_sys_lst.setModelColumn(0)
self.inp_sys_lst.setObjectName("inp_sys_lst")
self.gr_sys.addWidget(self.inp_sys_lst, 0, 0, 1, 1)
self.formLayout_2.setLayout(0, QtWidgets.QFormLayout.FieldRole, self.gr_sys)
self.btn_add = QtWidgets.QPushButton(self.tab_route)
self.btn_add.setObjectName("btn_add")
self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.btn_add)
self.inp_sys = QtWidgets.QLineEdit(self.tab_route)
self.inp_sys.setObjectName("inp_sys")
self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.inp_sys)
self.btn_rm = QtWidgets.QPushButton(self.tab_route)
self.btn_rm.setObjectName("btn_rm")
self.formLayout_2.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.btn_rm)
self.gr_mode = QtWidgets.QGridLayout()
self.gr_mode.setObjectName("gr_mode")
self.rd_comp = QtWidgets.QRadioButton(self.tab_route)
self.rd_comp.setChecked(True)
self.rd_comp.setObjectName("rd_comp")
self.gr_mode.addWidget(self.rd_comp, 0, 1, 1, 1)
self.rd_precomp = QtWidgets.QRadioButton(self.tab_route)
self.rd_precomp.setObjectName("rd_precomp")
self.gr_mode.addWidget(self.rd_precomp, 0, 2, 1, 1)
self.formLayout_2.setLayout(3, QtWidgets.QFormLayout.FieldRole, self.gr_mode)
self.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.gridLayout_4 = QtWidgets.QGridLayout()
self.gridLayout_4.setObjectName("gridLayout_4")
self.chk_permute_keep_last = QtWidgets.QCheckBox(self.tab_route)
self.chk_permute_keep_last.setObjectName("chk_permute_keep_last")
self.gridLayout_4.addWidget(self.chk_permute_keep_last, 0, 3, 1, 1)
self.chk_permute_keep_first = QtWidgets.QCheckBox(self.tab_route)
sizePolicy = QtWidgets.QSizePolicy(
QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed
)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(
self.chk_permute_keep_first.sizePolicy().hasHeightForWidth()
)
self.chk_permute_keep_first.setSizePolicy(sizePolicy)
self.chk_permute_keep_first.setTristate(False)
self.chk_permute_keep_first.setObjectName("chk_permute_keep_first")
self.gridLayout_4.addWidget(self.chk_permute_keep_first, 0, 2, 1, 1)
self.lbl_keep = QtWidgets.QLabel(self.tab_route)
sizePolicy = QtWidgets.QSizePolicy(
QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred
)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.lbl_keep.sizePolicy().hasHeightForWidth())
self.lbl_keep.setSizePolicy(sizePolicy)
self.lbl_keep.setObjectName("lbl_keep")
self.gridLayout_4.addWidget(self.lbl_keep, 0, 1, 1, 1)
self.formLayout_2.setLayout(
4, QtWidgets.QFormLayout.FieldRole, self.gridLayout_4
)
self.lst_sys = QtWidgets.QTreeWidget(self.tab_route)
sizePolicy = QtWidgets.QSizePolicy(
QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding
)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.lst_sys.sizePolicy().hasHeightForWidth())
self.lst_sys.setSizePolicy(sizePolicy)
self.lst_sys.setMinimumSize(QtCore.QSize(0, 0))
self.lst_sys.setDragEnabled(True)
self.lst_sys.setDragDropOverwriteMode(False)
self.lst_sys.setDragDropMode(QtWidgets.QAbstractItemView.InternalMove)
self.lst_sys.setDefaultDropAction(QtCore.Qt.MoveAction)
self.lst_sys.setAlternatingRowColors(True)
self.lst_sys.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
self.lst_sys.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
self.lst_sys.setHeaderHidden(True)
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.lbl_range = QtWidgets.QLabel(self.tab_route)
self.lbl_range.setObjectName("lbl_range")
self.formLayout_2.setWidget(8, QtWidgets.QFormLayout.LabelRole, self.lbl_range)
self.sb_range = QtWidgets.QDoubleSpinBox(self.tab_route)
self.sb_range.setObjectName("sb_range")
self.formLayout_2.setWidget(8, QtWidgets.QFormLayout.FieldRole, self.sb_range)
self.gr_opts = QtWidgets.QGridLayout()
self.gr_opts.setObjectName("gr_opts")
self.cmb_mode = QtWidgets.QComboBox(self.tab_route)
self.cmb_mode.setObjectName("cmb_mode")
self.cmb_mode.addItem("")
self.cmb_mode.addItem("")
self.cmb_mode.addItem("")
self.gr_opts.addWidget(self.cmb_mode, 0, 2, 1, 1)
self.lbl_greedyness = QtWidgets.QLabel(self.tab_route)
self.lbl_greedyness.setEnabled(True)
self.lbl_greedyness.setObjectName("lbl_greedyness")
self.gr_opts.addWidget(self.lbl_greedyness, 1, 1, 1, 1)
self.chk_primary = QtWidgets.QCheckBox(self.tab_route)
self.chk_primary.setObjectName("chk_primary")
self.gr_opts.addWidget(self.chk_primary, 0, 3, 1, 1)
self.sld_greedyness = QtWidgets.QSlider(self.tab_route)
self.sld_greedyness.setMaximum(100)
self.sld_greedyness.setPageStep(10)
self.sld_greedyness.setProperty("value", 50)
self.sld_greedyness.setOrientation(QtCore.Qt.Horizontal)
self.sld_greedyness.setTickPosition(QtWidgets.QSlider.TicksBelow)
self.sld_greedyness.setTickInterval(10)
self.sld_greedyness.setObjectName("sld_greedyness")
self.gr_opts.addWidget(self.sld_greedyness, 1, 2, 1, 2)
self.lbl_mode = QtWidgets.QLabel(self.tab_route)
self.lbl_mode.setObjectName("lbl_mode")
self.gr_opts.addWidget(self.lbl_mode, 0, 1, 1, 1)
self.formLayout_2.setLayout(9, 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(10, QtWidgets.QFormLayout.LabelRole, self.btn_go)
self.tabs.addTab(self.tab_route, "")
self.tab_log = QtWidgets.QWidget()
self.tab_log.setObjectName("tab_log")
self.gridLayout_3 = QtWidgets.QGridLayout(self.tab_log)
self.gridLayout_3.setObjectName("gridLayout_3")
self.txt_log = QtWidgets.QTextEdit(self.tab_log)
self.txt_log.setEnabled(True)
self.txt_log.setFrameShadow(QtWidgets.QFrame.Sunken)
self.txt_log.setLineWidth(1)
self.txt_log.setReadOnly(True)
self.txt_log.setAcceptRichText(False)
self.txt_log.setObjectName("txt_log")
self.gridLayout_3.addWidget(self.txt_log, 0, 0, 1, 1)
self.tabs.addTab(self.tab_log, "")
self.verticalLayout.addWidget(self.tabs)
ED_LRR.setCentralWidget(self.centralwidget)
self.menu = QtWidgets.QMenuBar(ED_LRR)
self.menu.setGeometry(QtCore.QRect(0, 0, 577, 21))
self.menu.setObjectName("menu")
self.menu_file = QtWidgets.QMenu(self.menu)
self.menu_file.setObjectName("menu_file")
self.menuWindow = QtWidgets.QMenu(self.menu)
self.menuWindow.setObjectName("menuWindow")
self.menuStyle = QtWidgets.QMenu(self.menuWindow)
self.menuStyle.setObjectName("menuStyle")
ED_LRR.setMenuBar(self.menu)
self.bar_status = QtWidgets.QStatusBar(ED_LRR)
self.bar_status.setObjectName("bar_status")
ED_LRR.setStatusBar(self.bar_status)
self.menu_act_quit = QtWidgets.QAction(ED_LRR)
self.menu_act_quit.setObjectName("menu_act_quit")
self.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())
self.retranslateUi(ED_LRR)
self.tabs.setCurrentIndex(2)
self.menu_act_quit.triggered.connect(ED_LRR.close)
QtCore.QMetaObject.connectSlotsByName(ED_LRR)
ED_LRR.setTabOrder(self.rd_comp, self.cmb_mode)
ED_LRR.setTabOrder(self.cmb_mode, self.chk_primary)
ED_LRR.setTabOrder(self.chk_primary, self.sld_greedyness)
ED_LRR.setTabOrder(self.sld_greedyness, self.rd_precomp)
def retranslateUi(self, ED_LRR):
_translate = QtCore.QCoreApplication.translate
ED_LRR.setWindowTitle(
_translate("ED_LRR", "Elite: Dangerous Long Range Route Plotter")
)
self.lbl_bodies_dl.setText(_translate("ED_LRR", "bodies.json"))
self.lbl_systems_dl.setText(_translate("ED_LRR", "systemsWithCoordinates.json"))
self.inp_bodies_dl.setCurrentText(
_translate("ED_LRR", "https://www.edsm.net/dump/bodies.json")
)
self.inp_systems_dl.setCurrentText(
_translate(
"ED_LRR", "https://www.edsm.net/dump/systemsWithCoordinates.json"
)
)
self.btn_bodies_dest_browse_dl.setText(_translate("ED_LRR", "..."))
self.btn_systems_dest_browse_dl.setText(_translate("ED_LRR", "..."))
self.btn_download.setText(_translate("ED_LRR", "Download"))
self.label.setText(_translate("ED_LRR", "Download path"))
self.label_2.setText(_translate("ED_LRR", "Download path"))
self.tabs.setTabText(
self.tabs.indexOf(self.tab_download), _translate("ED_LRR", "Download")
)
self.lbl_bodies_pp.setText(_translate("ED_LRR", "bodies.json"))
self.btn_bodies_browse_pp.setText(_translate("ED_LRR", "..."))
self.lbl_systems_pp.setText(_translate("ED_LRR", "systemsWithCoordinates.json"))
self.btn_systems_browse_pp.setText(_translate("ED_LRR", "..."))
self.lbl_out_pp.setText(_translate("ED_LRR", "Output"))
self.btn_out_browse_pp.setText(_translate("ED_LRR", "..."))
self.btn_preprocess.setText(_translate("ED_LRR", "Preprocess"))
self.tabs.setTabText(
self.tabs.indexOf(self.tab_preprocess), _translate("ED_LRR", "Preprocess")
)
self.lbl_sys_lst.setText(_translate("ED_LRR", "System List"))
self.btn_sys_lst_browse.setText(_translate("ED_LRR", "..."))
self.btn_add.setText(_translate("ED_LRR", "Add"))
self.inp_sys.setPlaceholderText(_translate("ED_LRR", "System Name"))
self.btn_rm.setText(_translate("ED_LRR", "Remove"))
self.rd_comp.setText(_translate("ED_LRR", "Compute Route"))
self.rd_precomp.setText(_translate("ED_LRR", "Precompute Graph"))
self.chk_permute.setText(_translate("ED_LRR", "Permute"))
self.chk_permute_keep_last.setText(_translate("ED_LRR", "Last"))
self.chk_permute_keep_first.setText(_translate("ED_LRR", "First"))
self.lbl_keep.setText(_translate("ED_LRR", "Keep Endpoints:"))
self.lst_sys.headerItem().setText(1, _translate("ED_LRR", "Type"))
self.lbl_range.setText(_translate("ED_LRR", "Jump Range (Ly)"))
self.cmb_mode.setCurrentText(_translate("ED_LRR", "Breadth-First Search"))
self.cmb_mode.setItemText(0, _translate("ED_LRR", "Breadth-First Search"))
self.cmb_mode.setItemText(1, _translate("ED_LRR", "Greedy-Search"))
self.cmb_mode.setItemText(2, _translate("ED_LRR", "A*-Search"))
self.lbl_greedyness.setText(_translate("ED_LRR", "Greedyness Factor"))
self.chk_primary.setText(_translate("ED_LRR", "Primary Stars Only"))
self.lbl_mode.setText(_translate("ED_LRR", "Mode"))
self.btn_go.setText(_translate("ED_LRR", "GO!"))
self.tabs.setTabText(
self.tabs.indexOf(self.tab_route), _translate("ED_LRR", "Route")
)
self.tabs.setTabText(
self.tabs.indexOf(self.tab_log), _translate("ED_LRR", "Log")
)
self.menu_file.setTitle(_translate("ED_LRR", "File"))
self.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"))

710
ed_lrr_gui/gui/ed_lrr.ui Normal file
View File

@ -0,0 +1,710 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ED_LRR</class>
<widget class="QMainWindow" name="ED_LRR">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>577</width>
<height>500</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>577</width>
<height>500</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>577</width>
<height>500</height>
</size>
</property>
<property name="windowTitle">
<string>Elite: Dangerous Long Range Route Plotter</string>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="documentMode">
<bool>false</bool>
</property>
<property name="tabShape">
<enum>QTabWidget::Rounded</enum>
</property>
<widget class="QWidget" name="centralwidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTabWidget" name="tabs">
<property name="enabled">
<bool>true</bool>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="tabPosition">
<enum>QTabWidget::North</enum>
</property>
<property name="tabShape">
<enum>QTabWidget::Rounded</enum>
</property>
<property name="currentIndex">
<number>2</number>
</property>
<property name="elideMode">
<enum>Qt::ElideNone</enum>
</property>
<property name="tabsClosable">
<bool>false</bool>
</property>
<property name="tabBarAutoHide">
<bool>false</bool>
</property>
<widget class="QWidget" name="tab_download">
<attribute name="title">
<string>Download</string>
</attribute>
<layout class="QFormLayout" name="formLayout">
<item row="1" column="0">
<widget class="QLabel" name="lbl_bodies_dl">
<property name="text">
<string>bodies.json</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="lbl_systems_dl">
<property name="text">
<string>systemsWithCoordinates.json</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="inp_bodies_dl">
<property name="editable">
<bool>true</bool>
</property>
<property name="currentText">
<string>https://www.edsm.net/dump/bodies.json</string>
</property>
<property name="insertPolicy">
<enum>QComboBox::InsertAtTop</enum>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="inp_systems_dl">
<property name="editable">
<bool>true</bool>
</property>
<property name="currentText">
<string>https://www.edsm.net/dump/systemsWithCoordinates.json</string>
</property>
<property name="insertPolicy">
<enum>QComboBox::InsertAtTop</enum>
</property>
</widget>
</item>
<item row="2" column="1">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QComboBox" name="inp_bodies_dest_dl">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="editable">
<bool>false</bool>
</property>
<property name="insertPolicy">
<enum>QComboBox::InsertAtTop</enum>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="btn_bodies_dest_browse_dl">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="4" column="1">
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="1">
<widget class="QPushButton" name="btn_systems_dest_browse_dl">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QComboBox" name="inp_systems_dest_dl">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="editable">
<bool>false</bool>
</property>
<property name="insertPolicy">
<enum>QComboBox::InsertAtTop</enum>
</property>
</widget>
</item>
</layout>
</item>
<item row="5" column="0">
<widget class="QPushButton" name="btn_download">
<property name="text">
<string>Download</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Download path</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Download path</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_preprocess">
<attribute name="title">
<string>Preprocess</string>
</attribute>
<layout class="QFormLayout" name="formLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="lbl_bodies_pp">
<property name="text">
<string>bodies.json</string>
</property>
</widget>
</item>
<item row="0" column="1">
<layout class="QGridLayout" name="gr_bodies_pp">
<item row="0" column="1">
<widget class="QPushButton" name="btn_bodies_browse_pp">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QComboBox" name="inp_bodies_pp">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="editable">
<bool>false</bool>
</property>
<property name="insertPolicy">
<enum>QComboBox::InsertAtTop</enum>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QLabel" name="lbl_systems_pp">
<property name="text">
<string>systemsWithCoordinates.json</string>
</property>
</widget>
</item>
<item row="1" column="1">
<layout class="QGridLayout" name="gr_systems_pp">
<item row="0" column="1">
<widget class="QPushButton" name="btn_systems_browse_pp">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QComboBox" name="inp_systems_pp">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="editable">
<bool>false</bool>
</property>
<property name="insertPolicy">
<enum>QComboBox::InsertAtTop</enum>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0">
<widget class="QLabel" name="lbl_out_pp">
<property name="text">
<string>Output</string>
</property>
</widget>
</item>
<item row="2" column="1">
<layout class="QGridLayout" name="gr_out_grid_pp">
<item row="0" column="1">
<widget class="QPushButton" name="btn_out_browse_pp">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QComboBox" name="inp_out_pp">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="editable">
<bool>false</bool>
</property>
<property name="insertPolicy">
<enum>QComboBox::InsertAtTop</enum>
</property>
</widget>
</item>
</layout>
</item>
<item row="3" column="0">
<widget class="QPushButton" name="btn_preprocess">
<property name="text">
<string>Preprocess</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_route">
<attribute name="title">
<string>Route</string>
</attribute>
<layout class="QFormLayout" name="formLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="lbl_sys_lst">
<property name="text">
<string>System List</string>
</property>
</widget>
</item>
<item row="0" column="1">
<layout class="QGridLayout" name="gr_sys">
<item row="0" column="1">
<widget class="QPushButton" name="btn_sys_lst_browse">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QComboBox" name="inp_sys_lst">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="editable">
<bool>false</bool>
</property>
<property name="insertPolicy">
<enum>QComboBox::InsertAtTop</enum>
</property>
<property name="frame">
<bool>true</bool>
</property>
<property name="modelColumn">
<number>0</number>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="btn_add">
<property name="text">
<string>Add</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="inp_sys">
<property name="placeholderText">
<string>System Name</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QPushButton" name="btn_rm">
<property name="text">
<string>Remove</string>
</property>
</widget>
</item>
<item row="3" column="1">
<layout class="QGridLayout" name="gr_mode">
<item row="0" column="1">
<widget class="QRadioButton" name="rd_comp">
<property name="text">
<string>Compute Route</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QRadioButton" name="rd_precomp">
<property name="text">
<string>Precompute Graph</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="chk_permute">
<property name="text">
<string>Permute</string>
</property>
</widget>
</item>
<item row="4" column="1">
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="3">
<widget class="QCheckBox" name="chk_permute_keep_last">
<property name="text">
<string>Last</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QCheckBox" name="chk_permute_keep_first">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>First</string>
</property>
<property name="tristate">
<bool>false</bool>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="lbl_keep">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Keep Endpoints:</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="7" column="0" colspan="2">
<widget class="QTreeWidget" name="lst_sys">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="dragEnabled">
<bool>true</bool>
</property>
<property name="dragDropOverwriteMode">
<bool>false</bool>
</property>
<property name="dragDropMode">
<enum>QAbstractItemView::InternalMove</enum>
</property>
<property name="defaultDropAction">
<enum>Qt::MoveAction</enum>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="headerHidden">
<bool>true</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>
</property>
</column>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="lbl_range">
<property name="text">
<string>Jump Range (Ly)</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QDoubleSpinBox" name="sb_range"/>
</item>
<item row="9" column="0" colspan="2">
<layout class="QGridLayout" name="gr_opts">
<item row="0" column="2">
<widget class="QComboBox" name="cmb_mode">
<property name="currentText">
<string>Breadth-First Search</string>
</property>
<item>
<property name="text">
<string>Breadth-First Search</string>
</property>
</item>
<item>
<property name="text">
<string>Greedy-Search</string>
</property>
</item>
<item>
<property name="text">
<string>A*-Search</string>
</property>
</item>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="lbl_greedyness">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Greedyness Factor</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QCheckBox" name="chk_primary">
<property name="text">
<string>Primary Stars Only</string>
</property>
</widget>
</item>
<item row="1" column="2" colspan="2">
<widget class="QSlider" name="sld_greedyness">
<property name="maximum">
<number>100</number>
</property>
<property name="pageStep">
<number>10</number>
</property>
<property name="value">
<number>50</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::TicksBelow</enum>
</property>
<property name="tickInterval">
<number>10</number>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="lbl_mode">
<property name="text">
<string>Mode</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="10" column="0">
<widget class="QPushButton" name="btn_go">
<property name="text">
<string>GO!</string>
</property>
<property name="flat">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_log">
<attribute name="title">
<string>Log</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QTextEdit" name="txt_log">
<property name="enabled">
<bool>true</bool>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<property name="lineWidth">
<number>1</number>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
<property name="acceptRichText">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menu">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>577</width>
<height>21</height>
</rect>
</property>
<widget class="QMenu" name="menu_file">
<property name="title">
<string>File</string>
</property>
<addaction name="menu_act_quit"/>
</widget>
<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"/>
</widget>
<widget class="QStatusBar" name="bar_status"/>
<action name="menu_act_quit">
<property name="text">
<string>Quit</string>
</property>
<property name="shortcut">
<string>Ctrl+Q</string>
</property>
</action>
<action name="actionA">
<property name="text">
<string>A</string>
</property>
</action>
<action name="actionB">
<property name="text">
<string>B</string>
</property>
</action>
</widget>
<tabstops>
<tabstop>rd_comp</tabstop>
<tabstop>cmb_mode</tabstop>
<tabstop>chk_primary</tabstop>
<tabstop>sld_greedyness</tabstop>
<tabstop>rd_precomp</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>menu_act_quit</sender>
<signal>triggered()</signal>
<receiver>ED_LRR</receiver>
<slot>close()</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>288</x>
<y>249</y>
</hint>
</hints>
</connection>
</connections>
</ui>

681
ed_lrr_gui/gui/main.py Normal file
View File

@ -0,0 +1,681 @@
import csv
import gzip
import multiprocessing as MP
import os
import pathlib
import queue
import sys
from sys import exit
from datetime import datetime, timedelta
from urllib.request import Request, urlopen
import _ed_lrr
import ed_lrr_gui
import requests as RQ
from ed_lrr_gui import Preprocessor, Router, cfg
from ed_lrr_gui.gui.ed_lrr import Ui_ED_LRR
from ed_lrr_gui.gui.widget_route import Ui_diag_route
from PyQt5.QtCore import QObject, Qt, QThread, QTimer, pyqtSignal
from PyQt5.QtGui import QColor, QPalette, QIcon
from PyQt5.QtWidgets import (
QAction,
QApplication,
QFileDialog,
QMainWindow,
QMessageBox,
QProgressDialog,
QTreeWidgetItem,
QLabel,
QDialog,
)
class ProgressDialog(QProgressDialog):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setWindowModality(Qt.WindowModal)
def sizeof_fmt(num, suffix="B"):
for unit in ["", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"]:
if abs(num) < 1024.0:
return "{:.02f} {}{}".format(num, unit, suffix)
num /= 1024.0
return "{:.02f} {}{}".format(num, "Yi", suffix)
def t_round(dt):
return dt - dt % timedelta(seconds=1)
class Job(QObject):
progress = pyqtSignal("PyQt_PyObject")
def __init__(self, app, main_window, cls, *args, **kwargs):
super().__init__()
self.job = cls(*args, **kwargs)
self.timer = QTimer(app)
self.app = app
self.main_window = main_window
self.timer.timeout.connect(self.interval)
self.timer.start(100)
self.last_val = None
self.progress_dialog = None
self.state = {}
self.setup_progress(self.handle_progess)
def setup_progress(self, handle_progess):
self.progress.connect(lambda *args, **kwargs: handle_progess(*args, **kwargs))
def handle_progess(self, *args, **kwargs):
raise NotImplementedError
def start(self):
if self.progress_dialog is None:
self.progress.connect(
lambda *args, **kwargs: print("PROGRESS:", *args, **kwargs)
)
self.started = datetime.today()
return self.job.start()
def cancel(self):
self.job.terminate()
self.job = None
def __bool__(self):
return not self.done
@property
def done(self):
if self.job:
return (self.job.is_alive() == False) and (self.job.queue.empty())
return True
def interval(self):
while self:
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 PreprocessJob(Job):
def __init__(self, app, main_window, *args, **kwargs):
super().__init__(app, main_window, Preprocessor, *args, **kwargs)
self.progress_dialog = ProgressDialog("", "Cancel", 0, 0, self.main_window)
self.progress_dialog.setAutoClose(False)
self.progress_dialog.canceled.connect(self.cancel)
self.progress_dialog.show()
self.start()
def handle_progess(self, state):
sent = object()
if state.get("return", sent) != sent:
self.progress_dialog.close()
return
msg = "Processed: {}/{}".format(
sizeof_fmt(state["status"]["done"]), sizeof_fmt(state["status"]["total"])
)
state["status"]["prc_done"] = (
state["status"]["done"] / state["status"]["total"]
) * 100
title = "[{prc_done:.2f}%] Processing {file}".format(**state["status"])
self.progress_dialog.setMinimum(0)
self.progress_dialog.setMaximum(100 * 100)
self.progress_dialog.setWindowTitle(title)
self.progress_dialog.setLabelText(msg)
self.progress_dialog.setValue(int(state["status"]["prc_done"] * 100))
class RouterJob(Job):
def __init__(self, app, main_window, *args, **kwargs):
super().__init__(app, main_window, Router, *args, **kwargs)
self.progress_dialog = ProgressDialog("", "Cancel", 0, 0, self.main_window)
self.progress_dialog.setAutoClose(False)
self.progress_dialog.setLabelText("Loading data (this will take a bit) ...")
self.progress_dialog.setWindowTitle("Loading...")
self.progress_dialog.canceled.connect(self.cancel)
self.progress_dialog.show()
self.start()
self.state = {}
def handle_progess(self, state):
sent = object()
if state.get("return", sent) != sent:
print(state["return"])
self.progress_dialog.close()
route_win = WRoute(self.main_window, state["return"])
return
msg = "Depth: {depth}\nBody: {body}\nQueued: {queue_size}\nDistance remaining: {d_rem:.2f} Ly".format(
**state["status"]
)
title = "[{prc_done:.2f}%] Plotting route from [{from}] to [{to}]".format(
**state["status"]
)
self.progress_dialog.setMinimum(0)
self.progress_dialog.setMaximum(100 * 100)
self.progress_dialog.setWindowTitle(title)
self.progress_dialog.setLabelText(msg)
self.progress_dialog.setValue(int(state["status"]["prc_done"] * 100))
class DownloadThread(QThread):
progress = pyqtSignal("PyQt_PyObject")
def __init__(self, systems_url, systems_file, bodies_url, bodies_file):
super().__init__()
self.systems_url = systems_url
self.systems_file = systems_file
self.bodies_url = bodies_url
self.bodies_file = bodies_file
self.running = True
def __del__(self):
self.wait()
def stop(self):
self.running = False
def run(self):
dl_jobs = [
(self.systems_url, self.systems_file),
(self.bodies_url, self.bodies_file),
]
for url, dest in dl_jobs:
outfile = url.split("/")[-1]
size = RQ.head(url, headers={"Accept-Encoding": "None"})
size.raise_for_status()
size = int(size.headers.get("Content-Length", 0))
with open(dest, "wb") as of:
resp = RQ.get(url, stream=True)
for chunk in resp.iter_content(1024 * 1024):
of.write(chunk)
self.progress.emit(
{"done": of.tell(), "size": size, "outfile": outfile}
)
if not self.running:
return
class App(QApplication):
def __init__(self):
super().__init__(sys.argv)
self.setStyle("Fusion")
self.setup_styles()
def set_style(self, style):
print("LOAD:", style)
self.setPalette(self.styles[style])
def setup_styles(self):
self.styles = {}
styles = {
"Dark": {
"Window": QColor(53, 53, 53),
"WindowText": Qt.white,
"Base": QColor(15, 15, 15),
"AlternateBase": QColor(53, 53, 53),
"ToolTipBase": Qt.white,
"ToolTipText": Qt.white,
"Text": Qt.white,
"Button": QColor(53, 53, 53),
"ButtonText": Qt.white,
"BrightText": Qt.red,
"Highlight": QColor(255, 128, 0),
"HighlightedText": Qt.black,
}
}
for style, colors in styles.items():
palette = QPalette()
for entry, color in colors.items():
palette.setColor(getattr(QPalette, entry), color)
if color == Qt.darkGray:
palette.setColor(
QPalette.Disabled, getattr(QPalette, entry), QColor(53, 53, 53)
)
else:
palette.setColor(
QPalette.Disabled, getattr(QPalette, entry), Qt.darkGray
)
self.styles[style] = palette
self.styles["Light"] = self.style().standardPalette()
class WRoute(Ui_diag_route):
def __init__(self, main_window, hops):
super().__init__()
self.route = hops
dialog = QDialog(main_window)
self.setupUi(dialog)
for n, item in enumerate(hops):
if item["body"].startswith(item["system"]):
item["body"] = item["body"].replace(item["system"], "").strip()
item = QTreeWidgetItem(
self.lst_route,
[
str(n + 1),
item["system"],
"{body} ({star_type})".format(**item),
str(item["distance"]),
"<NotImplemented>", # Jump distance
],
)
item.setFlags(item.flags() & ~Qt.ItemIsDropEnabled)
dialog.exec_()
class ED_LRR(Ui_ED_LRR):
dl_thread = None
diag_prog = None
dl_started = None
system_found = pyqtSignal("PyQt_PyObject")
def __init__(self):
super().__init__()
self.current_job = None
def get_open_file(self, filetypes, callback=None):
fileName, _ = QFileDialog.getOpenFileName(
self.main_window,
"Open file",
cfg["folders.data_dir"],
filetypes,
options=QFileDialog.DontUseNativeDialog,
)
if callback:
return callback(fileName)
return fileName
def get_save_file(self, filetypes, callback=None):
fileName, _ = QFileDialog.getSaveFileName(
self.main_window,
"Save file",
cfg["folders.data_dir"],
filetypes,
options=QFileDialog.DontUseNativeDialog,
)
if callback:
return callback(fileName)
return fileName
def preprocess(self):
if self.current_job:
# ERROR
return
bodies_json = self.inp_bodies_pp.currentText()
systems_json = self.inp_systems_pp.currentText()
output_file = self.inp_out_pp.currentText()
self.current_job = PreprocessJob(
self.app, self.main_window, systems_json, bodies_json, output_file
)
def set_sys_lst(self, path):
if path not in cfg["history.stars_csv_path"]:
cfg["history.stars_csv_path"].append(path)
self.update_dropdowns()
def set_bodies_file(self, path):
if path not in cfg["history.bodies_path"]:
cfg["history.bodies_path"].append(path)
self.update_dropdowns()
def set_systems_file(self, path):
if path not in cfg["history.systems_path"]:
cfg["history.systems_path"].append(path)
self.update_dropdowns()
def update_dropdowns(self):
self.inp_systems_pp.clear()
self.inp_systems_dest_dl.clear()
for path in cfg["history.systems_path"][:]:
self.inp_systems_pp.addItem(path)
self.inp_systems_pp.setCurrentText(path)
self.inp_systems_dest_dl.addItem(path)
self.inp_systems_dest_dl.setCurrentText(path)
self.inp_bodies_pp.clear()
self.inp_bodies_dest_dl.clear()
for path in cfg["history.bodies_path"][:]:
self.inp_bodies_pp.addItem(path)
self.inp_bodies_pp.setCurrentText(path)
self.inp_bodies_dest_dl.addItem(path)
self.inp_bodies_dest_dl.setCurrentText(path)
self.inp_sys_lst.clear()
self.inp_out_pp.clear()
for path in cfg["history.stars_csv_path"]:
self.inp_sys_lst.addItem(path)
self.inp_sys_lst.setCurrentText(path)
self.inp_out_pp.addItem(path)
self.inp_out_pp.setCurrentText(path)
return
def log(self, *args):
t = datetime.today()
msg_t = "[{}] {}".format(t, str.format(*args))
self.txt_log.append(msg_t)
def set_comp_mode(self, _):
if self.rd_comp.isChecked():
comp_mode = "Compute Route"
self.btn_add.setText("Add")
if self.rd_precomp.isChecked():
comp_mode = "Precompute Graph"
self.btn_add.setText("Select")
self.log("COMP_MODE", comp_mode)
self.lst_sys.setEnabled(self.rd_comp.isChecked())
self.btn_rm.setEnabled(self.rd_comp.isChecked())
self.cmb_mode.setEnabled(self.rd_comp.isChecked())
self.chk_permute.setEnabled(self.rd_comp.isChecked())
self.lbl_keep.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_last.setEnabled(self.rd_comp.isChecked())
self.set_route_mode(self.rd_precomp.isChecked() or None)
def set_route_mode(self, mode=None):
if mode == None:
mode = self.cmb_mode.currentText()
self.lbl_greedyness.setEnabled(mode == "A*-Search")
self.sld_greedyness.setEnabled(mode == "A*-Search")
def set_greedyness(self, value):
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):
header = [
self.lst_sys.headerItem().data(c, 0)
for c in range(self.lst_sys.headerItem().columnCount())
]
system = [
self.lst_sys.topLevelItem(n).data(c, 0)
for c in range(self.lst_sys.topLevelItem(n).columnCount())
]
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, "ED_LRR 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 compute_route(self):
self.bar_status.showMessage("Resolving systems...")
num_resolved = self.resolve_systems()
if num_resolved:
if (
QMessageBox.question(
self.main_window,
"ED_LRR",
"Resolved {} system(s), are the names correct?".format(
num_resolved
),
)
== QMessageBox.No
):
return
self.bar_status.clearMessage()
print(self.systems)
systems = [str(s["id"]) for s in self.systems]
jump_range = self.sb_range.value()
if jump_range == 0:
self.error(
"Your jump range is set to zero, you're not going to get anywhere that way"
)
return
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
)
path = self.get_sys_list()
if path is None:
return
precomp = None
path = str(path)
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,
)
if not self.current_job:
self.bar_status.showMessage("Computing Route...")
self.current_job = RouterJob(
self.app,
self.main_window,
systems,
jump_range,
None,
mode,
primary,
permute,
keep_first,
keep_last,
greedyness,
precomp,
path,
)
else:
self.error("there is already a job running!")
def find_sys_by_names(self, names):
t_s = datetime.today()
if not self.get_sys_list():
return None
# TODO: start thread/subprocess
ret = _ed_lrr.find_sys(names, self.inp_sys_lst.currentText())
print("Took:", datetime.today() - t_s)
return ret
def resolve_systems(self):
# TODO: show spinner
names = []
nums = []
for n in range(self.lst_sys.topLevelItemCount()):
sys_id = getattr(self.lst_sys.topLevelItem(n), "__id__", None)
if sys_id is not None:
continue
names.append(self.sys_to_dict(n)["Name"])
nums.append(n)
if not names:
return 0
systems = self.find_sys_by_names(names)
if systems is None:
return
for i, name in zip(nums, 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"]
return len(names)
# diff, item = self.find_sys_by_name(name)
# print("Found", (diff, item))
def add_system(self):
name = self.inp_sys.text()
item = QTreeWidgetItem(self.lst_sys, [name, None])
item.resolved = False
item.setFlags(item.flags() & ~Qt.ItemIsDropEnabled)
def remove_system(self):
root = self.lst_sys.invisibleRootItem()
for item in self.lst_sys.selectedItems():
root.removeChild(item)
def dl_canceled(self):
if self.dl_thread:
print("Cancel!")
try:
self.dl_thread.progress.disconnect()
except TypeError:
pass
self.dl_thread.stop()
self.dl_thread.wait()
self.diag_prog.close()
self.dl_thread = None
self.diag_prog = None
self.dl_started = None
def handle_dl_progress(self, args):
filename = os.path.split(args["outfile"])[-1]
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"])
def run_download(self):
if self.dl_thread:
return
self.dl_started = datetime.today()
self.dl_thread = DownloadThread(
self.inp_systems_dl.currentText(),
self.inp_systems_dest_dl.currentText(),
self.inp_bodies_dl.currentText(),
self.inp_bodies_dest_dl.currentText(),
)
self.dl_thread.progress.connect(self.handle_dl_progress)
self.dl_thread.start()
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):
self.btn_download.clicked.connect(self.run_download)
self.set_greedyness(self.sld_greedyness.value())
self.cmb_mode.currentTextChanged.connect(self.set_route_mode)
self.rd_comp.toggled.connect(self.set_comp_mode)
self.rd_precomp.toggled.connect(self.set_comp_mode)
self.sld_greedyness.valueChanged.connect(self.set_greedyness)
self.btn_go.clicked.connect(self.compute_route)
self.btn_add.clicked.connect(self.add_system)
self.btn_rm.clicked.connect(self.remove_system)
self.btn_preprocess.clicked.connect(self.preprocess)
self.chk_permute.stateChanged.connect(self.update_permute_chk)
self.btn_out_browse_pp.clicked.connect(
lambda: self.get_save_file("CSV File (*.csv)", self.set_sys_lst)
)
self.btn_sys_lst_browse.clicked.connect(
lambda: self.get_open_file("CSV File (*.csv)", self.set_sys_lst)
)
self.btn_bodies_browse_pp.clicked.connect(
lambda: self.get_open_file("JSON File (*.json)", self.set_bodies_file)
)
self.btn_bodies_dest_browse_dl.clicked.connect(
lambda: self.get_save_file("JSON File (*.json)", self.set_bodies_file)
)
self.btn_systems_browse_pp.clicked.connect(
lambda: self.get_open_file("JSON File (*.json)", self.set_systems_file)
)
self.btn_systems_dest_browse_dl.clicked.connect(
lambda: self.get_save_file("JSON File (*.json)", self.set_systems_file)
)
def handle_close(self):
for key in [
"history.stars_csv_path",
"history.bodies_path",
"history.systems_path",
]:
for path in cfg[key][:]:
if not os.path.isfile(path):
cfg[key].remove(path)
cfg.write()
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):
super().setupUi(MainWindow)
self.update_dropdowns()
self.main_window = MainWindow
self.app = app
self.setup_signals()
self.lst_sys.setHeaderLabels(["Name", "Type"])
self.set_route_mode()
self.update_permute_chk(self.chk_permute.isChecked())
self.setup_styles(MainWindow, app)
def main():
MP.freeze_support()
app = App()
app.setWindowIcon(QIcon(r"D:\devel\rust\ed_lrr_gui\icon\icon.ico"))
MainWindow = QMainWindow()
MainWindow.setWindowIcon(QIcon(r"D:\devel\rust\ed_lrr_gui\icon\icon.ico"))
ui = ED_LRR()
ui.setupUi(MainWindow, app)
MainWindow.show()
ret = app.exec_()
ui.handle_close()
exit(ret)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,65 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'D:\devel\rust\ed_lrr_gui\ed_lrr_gui\gui\widget_route.ui'
#
# Created by: PyQt5 UI code generator 5.13.1
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_diag_route(object):
def setupUi(self, diag_route):
diag_route.setObjectName("diag_route")
diag_route.setWindowModality(QtCore.Qt.WindowModal)
diag_route.resize(430, 300)
self.layout_main = QtWidgets.QGridLayout(diag_route)
self.layout_main.setObjectName("layout_main")
self.layout_top = QtWidgets.QGridLayout()
self.layout_top.setObjectName("layout_top")
self.lst_route = QtWidgets.QTreeWidget(diag_route)
self.lst_route.setProperty("showDropIndicator", False)
self.lst_route.setDefaultDropAction(QtCore.Qt.IgnoreAction)
self.lst_route.setAlternatingRowColors(True)
self.lst_route.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection)
self.lst_route.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollPerItem)
self.lst_route.setHorizontalScrollMode(
QtWidgets.QAbstractItemView.ScrollPerPixel
)
self.lst_route.setItemsExpandable(False)
self.lst_route.setAllColumnsShowFocus(False)
self.lst_route.setObjectName("lst_route")
self.layout_top.addWidget(self.lst_route, 0, 0, 1, 1)
self.layout_main.addLayout(self.layout_top, 0, 0, 1, 1)
self.layout_bottom = QtWidgets.QGridLayout()
self.layout_bottom.setObjectName("layout_bottom")
self.chk_copy = QtWidgets.QCheckBox(diag_route)
self.chk_copy.setObjectName("chk_copy")
self.layout_bottom.addWidget(self.chk_copy, 1, 0, 1, 1)
self.btn_close = QtWidgets.QPushButton(diag_route)
self.btn_close.setObjectName("btn_close")
self.layout_bottom.addWidget(self.btn_close, 1, 2, 1, 1)
self.btn_export = QtWidgets.QPushButton(diag_route)
self.btn_export.setObjectName("btn_export")
self.layout_bottom.addWidget(self.btn_export, 1, 1, 1, 1)
self.layout_main.addLayout(self.layout_bottom, 1, 0, 1, 1)
self.retranslateUi(diag_route)
QtCore.QMetaObject.connectSlotsByName(diag_route)
def retranslateUi(self, diag_route):
_translate = QtCore.QCoreApplication.translate
diag_route.setWindowTitle(_translate("diag_route", "Route"))
self.lst_route.headerItem().setText(0, _translate("diag_route", "Num"))
self.lst_route.headerItem().setText(1, _translate("diag_route", "System"))
self.lst_route.headerItem().setText(2, _translate("diag_route", "Body"))
self.lst_route.headerItem().setText(
3, _translate("diag_route", "Distance (Ls)")
)
self.chk_copy.setText(
_translate("diag_route", "Auto-copy next hop to clipboard")
)
self.btn_close.setText(_translate("diag_route", "Close"))
self.btn_export.setText(_translate("diag_route", "Export"))

View File

@ -0,0 +1,101 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>diag_route</class>
<widget class="QDialog" name="diag_route">
<property name="windowModality">
<enum>Qt::WindowModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>430</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Route</string>
</property>
<layout class="QGridLayout" name="layout_main">
<item row="0" column="0">
<layout class="QGridLayout" name="layout_top">
<item row="0" column="0">
<widget class="QTreeWidget" name="lst_route">
<property name="showDropIndicator" stdset="0">
<bool>false</bool>
</property>
<property name="defaultDropAction">
<enum>Qt::IgnoreAction</enum>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
</property>
<property name="verticalScrollMode">
<enum>QAbstractItemView::ScrollPerItem</enum>
</property>
<property name="horizontalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
<property name="itemsExpandable">
<bool>false</bool>
</property>
<property name="allColumnsShowFocus">
<bool>false</bool>
</property>
<column>
<property name="text">
<string>Num</string>
</property>
</column>
<column>
<property name="text">
<string>System</string>
</property>
</column>
<column>
<property name="text">
<string>Body</string>
</property>
</column>
<column>
<property name="text">
<string>Distance (Ls)</string>
</property>
</column>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<layout class="QGridLayout" name="layout_bottom">
<item row="1" column="0">
<widget class="QCheckBox" name="chk_copy">
<property name="text">
<string>Auto-copy next hop to clipboard</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="btn_close">
<property name="text">
<string>Close</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="btn_export">
<property name="text">
<string>Export</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

1000
ed_lrr_gui/html_export.py Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,158 @@
<html>
<head>
<meta charset="utf-8"/>
<style>
h1 {
float: left;
}
body {
background: #222;
margin: 0px;
width: 100%;
height: 100%;
}
table {
border-collapse: collapse;
max-width: 50%;
float: right;
}
#graph {
border: 1px solid #eee;
float: left;
}
table,
td,
tr,th {
color: #eee;
margin: auto;
border: 1px solid #eee;
text-align: center;
}
/* D3 stuff */
.d3-tip {
line-height: 1;
font-weight: bold;
padding: 12px;
background: rgba(0, 0, 0, 0.8);
color: #fff;
border-radius: 2px;
}
/* Creates a small triangle extender for the tooltip */
.d3-tip:after {
box-sizing: border-box;
display: inline;
font-size: 10px;
width: 100%;
line-height: 1;
color: rgba(0, 0, 0, 0.8);
content: "\25BC";
position: absolute;
text-align: center;
}
/* Style northward tooltips differently */
.d3-tip.n:after {
margin: -1px 0 0 0;
top: 100%;
left: 0;
}
</style>
<script src="https://d3js.org/d3.v5.min.js"></script>
</head>
<body>
<div id="graph"></div>
<table>
<tr>
<th>Num</th>
<th>Body</th>
<th>Type</th>
<th>Distance to arrival</th>
<th>Jump range</th>
</tr>
{% for sys in route %}
<tr>
<td>{{sys.num}}</td>
<td>{{sys.body}}</td>
<td style="color: {{sys.color}}">{{sys.star_type}}</td>
<td>{{sys.distance}}</td>
<td>{{sys.jump_dist}}</td>
</tr>
{% endfor %}
</table>
<script type="text/javascript">
function dist(a,b) {
var sum=0;
for (var i=0;i<a.length;++i) {
sum+=Math.pow(a[i]-b[i],2)
}
return Math.pow(sum,0.5);
}
var width=512;
var height=512;
var route={{route|tojson}};
var vis=d3.select("#graph")
.append("svg").attr("viewBox", [0, 0, width, height]);;
vis.attr("width", width)
.attr("height", height);
var g=vis.append("g");
vis.call(d3.zoom()
.extent([[0, 0], [width, height]])
.on("zoom", () => {
g.attr("transform", d3.event.transform);
}));
var lines=[];
for (var i=0;i<route.length-1;++i) {
lines.push({
x1: route[i].pos[1],
x2: route[i+1].pos[1],
y1: -route[i].pos[2],
y2: -route[i+1].pos[2],
dist: dist(route[i].pos,route[i+1].pos),
color: ({
'#99A0FF':'#99A0FF', // Neutron star
'#5D67EF':'#5D67EF' // White dwarf
}[route[i].color]||'#eee')
})
}
g.selectAll(".line")
.data(lines)
.enter()
.append("line")
.attr("x1", (l) => l.x1 )
.attr("y1", (l) => l.y1 )
.attr("x2", (l) => l.x2 )
.attr("y2", (l) => l.y2 )
.style("stroke", (l) => l.color )
.style("stroke-width", 5)
.append("title")
.text((l) => Math.round(l.dist*100)/100 +" Ly");
g.selectAll("circle .nodes")
.data(route)
.enter()
.append("svg:circle")
.attr("class", "nodes")
.attr("cx", (d) => d.pos[1])
.attr("cy", (d) => -d.pos[2])
.attr("r", 10)
.attr("fill", (d) => d.color)
.append("title")
.text((d) => d.body+" ("+d.star_type+")")
</script>
</body>
</html>

35
ed_lrr_gui/preprocess.py Normal file
View File

@ -0,0 +1,35 @@
import queue
from collections import namedtuple
from datetime import datetime, timedelta
from multiprocessing import Process, Queue, freeze_support
import _ed_lrr
class Preprocessor(Process):
def __init__(self, *args, **kwargs):
super().__init__()
self.state = {}
self.queue = Queue()
self.daemon = True
self.args = args
self.kwargs = kwargs
self.kwargs["callback"] = self.callback
def callback(self, state):
self.queue.put({"status": state})
def run(self):
res = _ed_lrr.preprocess(*self.args, **self.kwargs)
self.queue.put({"result": res})
if __name__ == "__main__":
freeze_support()
r = Preprocessor(
r"D:\devel\rust\ED_LRR\dumps\systemsWithCoordinates.json",
r"D:\devel\rust\ED_LRR\dumps\bodies.json",
r"D:\devel\rust\ED_LRR\stars.csv",
)
for i, e in enumerate(r):
print(e)

40
ed_lrr_gui/router.py Normal file
View File

@ -0,0 +1,40 @@
import queue
from collections import namedtuple
from datetime import datetime, timedelta
from multiprocessing import Process, Queue, freeze_support
import _ed_lrr
class Router(Process):
def __init__(self, *args, **kwargs):
super().__init__()
self.state = {}
self.queue = Queue()
self.daemon = True
self.args = args
self.kwargs = kwargs
self.kwargs["callback"] = self.callback
def callback(self, state):
self.queue.put({"status": state})
def run(self):
route = _ed_lrr.route(*self.args, **self.kwargs)
self.queue.put({"return": route})
if __name__ == "__main__":
freeze_support()
r = Router(
["Ix", "Beagle Point"],
48,
"BFS",
False,
False,
None,
None,
r"D:\devel\rust\ED_LRR\stars.csv",
)
for e in r:
print(e)

View File

100
ed_lrr_gui/web/__main__.py Normal file
View File

@ -0,0 +1,100 @@
from flask import Flask, jsonify
import uuid
import json
from webargs import fields, validate
from webargs.flaskparser import use_args
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy_utils import Timestamp, generic_repr
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import scoped_session, sessionmaker, relationship, backref
from sqlalchemy.types import Float, String, Boolean
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///jobs.db"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db = SQLAlchemy(app)
@generic_repr
class Job(db.Model, Timestamp):
id = db.Column(db.String, default=lambda: str(uuid.uuid4()), primary_key=True)
jump_range = db.Column(db.Float, nullable=False)
mode = db.Column(db.String, default="bfs")
systems = db.Column(db.String)
permute = db.Column(db.String, default=None, nullable=True)
primary = db.Column(db.Boolean, default=False)
factor = db.Column(db.Float, default=0.5)
done = db.Column(db.DateTime, nullable=True, default=None)
started = db.Column(db.DateTime, nullable=True, default=None)
progress = db.Column(db.Float, default=0.0)
# ============================================================
@classmethod
def new(cls, **kwargs):
obj = cls(**kwargs)
db.session.add(obj)
db.session.commit()
print(obj)
return obj
@property
def dict(self):
ret = {}
for col in self.__table__.columns:
ret[col.name] = getattr(self, col.name)
ret["systems"] = json.loads(ret["systems"])
return ret
@dict.setter
def set_dict(self, *args, **kwargs):
raise NotImplementedError
db.create_all()
db.session.commit()
@app.errorhandler(422)
@app.errorhandler(400)
def handle_error(err):
headers = err.data.get("headers", None)
messages = err.data.get("messages", ["Invalid request."])
if headers:
return jsonify({"errors": messages}), err.code, headers
else:
return jsonify({"errors": messages}), err.code
@app.route("/route", methods=["GET", "POST"])
@use_args(
{
"jump_range": fields.Float(required=True),
"mode": fields.String(
missing="bfs", validate=validate.OneOf(["bfs", "greedy", "a-star"])
),
"systems": fields.DelimitedList(fields.String, required=True),
"permute": fields.String(
missing=None,
validate=validate.OneOf(["all", "keep_first", "keep_last", "keep_both"]),
),
"primary": fields.Boolean(missing=False),
"factor": fields.Float(missing=0.5),
}
)
def route(args):
args["systems"] = json.dumps(args["systems"])
for k, v in args.items():
print(k, v)
return jsonify({"id": Job.new(**args).id})
@app.route("/status/<uuid:job_id>")
def status(job_id):
job = db.session.query(Job).get_or_404(str(job_id))
return jsonify(job.dict)
if __name__ == "__main__":
app.run(host="0.0.0.0", port=3777, debug=True)

BIN
icon/icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 368 KiB

133
icon/make.py Normal file
View File

@ -0,0 +1,133 @@
import svgwrite
import random
import time
from math import factorial, sin, cos, pi
from itertools import permutations
import tsp as m_tsp
def dist(p1, p2):
return dist2(p1, p2) ** 0.5
def dist2(p1, p2):
diff = 0
for a, b in zip(p1, p2):
diff += (a - b) ** 2
return diff
def tsp(points):
res = []
for idx in m_tsp.tsp(points)[1]:
res.append(points[idx])
return res
def make_points(n, size, min_dist=0):
min_dist *= min_dist
points = []
while len(points) < n:
px, py = random.random(), random.random()
px *= size / 2
py *= size / 2
px += 70
py += 70
valid = True
for p in points:
if dist2(p, (px, py)) < min_dist:
valid = False
break
if valid:
points.append((px, py))
print("{}/{}".format(len(points), n))
return points
def generate(seed, name=None, small=False):
sd = 1
if small:
sd = 2
random.seed(seed)
w = 2
max_rings = 3
num_points = 5
min_dist = 10 + 10 + 20 * (max_rings + 1)
base_r = 10
ring_step = lambda v: 10 + v * 10
size = 1000
if name is None:
name = seed
dwg = svgwrite.Drawing(filename="out/{}.svg".format(name))
dwg.defs.add(dwg.style(".background { fill: #222; }"))
dwg.add(dwg.rect(size=("100%", "100%"), class_="background"))
print("Generating points...")
color = "#eee"
pos = make_points(num_points, size, min_dist=min_dist)
print("TSP...")
pos = tsp(pos)
for (x1, y1), (x2, y2) in zip(pos, pos[1:]):
if small:
x1 /= sd
x2 /= sd
y1 /= sd
y2 /= sd
line = dwg.add(dwg.line((x1, y1), (x2, y2), stroke_width=w, stroke=color))
for (px, py) in pos:
base_r = 3
if small:
base_r = 5
px /= sd
py /= sd
if random.random() > 0.8:
dwg.add(
dwg.circle(
(px, py),
r=base_r + random.random() * base_r,
stroke_width=w,
stroke="#0ae",
)
).fill("#0ae")
else:
dwg.add(
dwg.circle(
(px, py),
r=base_r + random.random() * base_r,
stroke_width=w,
stroke=color,
)
).fill(color)
r = base_r
for _ in range(random.randint(1, max_rings)):
if small:
random.random()
random.random()
random.random()
continue
r += ring_step(random.random())
ring_col = color
if random.random() > 0.75:
ring_col = "#ea0"
circ = dwg.add(dwg.circle((px, py), r=r, stroke_width=w, stroke=ring_col))
circ.fill(color, opacity=0)
d = random.random() * pi * 2
dx = cos(d)
dy = sin(d)
m = random.random()
moon = dwg.add(
dwg.circle(
(px + dx * r, py + dy * r),
r=2 + 2 * m,
stroke_width=w,
stroke=ring_col,
)
)
moon.fill(ring_col)
dwg.save()
seed = -4
generate(seed, "icon_1", small=False)
generate(seed, "icon_1_small", small=True)

2
icon/out/icon_1.svg Normal file
View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8" ?>
<svg baseProfile="full" height="100%" version="1.1" width="100%" xmlns="http://www.w3.org/2000/svg" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"><![CDATA[.background { fill: #222; }]]></style></defs><rect class="background" height="100%" width="100%" x="0" y="0" /><line stroke="#eee" stroke-width="2" x1="188.02404486871725" x2="103.25754783979495" y1="121.5830171153579" y2="270.7955072425374" /><line stroke="#eee" stroke-width="2" x1="103.25754783979495" x2="528.9775215438594" y1="270.7955072425374" y2="470.2261757479043" /><line stroke="#eee" stroke-width="2" x1="528.9775215438594" x2="452.58130125271924" y1="470.2261757479043" y2="180.96408784515882" /><line stroke="#eee" stroke-width="2" x1="452.58130125271924" x2="338.3400040874068" y1="180.96408784515882" y2="208.34132172072512" /><circle cx="188.02404486871725" cy="121.5830171153579" fill="#eee" r="3.3185498772945903" stroke="#eee" stroke-width="2" /><circle cx="188.02404486871725" cy="121.5830171153579" fill="#eee" fill-opacity="0" r="22.429593602379832" stroke="#eee" stroke-width="2" /><circle cx="173.80179554276944" cy="104.23901834695114" fill="#eee" r="2.52050830126476" stroke="#eee" stroke-width="2" /><circle cx="103.25754783979495" cy="270.7955072425374" fill="#eee" r="3.4944547782059745" stroke="#eee" stroke-width="2" /><circle cx="103.25754783979495" cy="270.7955072425374" fill="#eee" fill-opacity="0" r="19.2697560241313" stroke="#eee" stroke-width="2" /><circle cx="115.03444741085107" cy="255.5433554690071" fill="#eee" r="3.7601015027223985" stroke="#eee" stroke-width="2" /><circle cx="103.25754783979495" cy="270.7955072425374" fill="#eee" fill-opacity="0" r="30.13693855048052" stroke="#eee" stroke-width="2" /><circle cx="89.02212054970202" cy="244.23260689141011" fill="#eee" r="3.0119075514208307" stroke="#eee" stroke-width="2" /><circle cx="528.9775215438594" cy="470.2261757479043" fill="#eee" r="4.420763662755435" stroke="#eee" stroke-width="2" /><circle cx="528.9775215438594" cy="470.2261757479043" fill="#eee" fill-opacity="0" r="22.44577790309402" stroke="#ea0" stroke-width="2" /><circle cx="549.9596596985477" cy="462.25354606049257" fill="#ea0" r="3.680925358835544" stroke="#ea0" stroke-width="2" /><circle cx="452.58130125271924" cy="180.96408784515882" fill="#eee" r="3.8758250081323116" stroke="#eee" stroke-width="2" /><circle cx="452.58130125271924" cy="180.96408784515882" fill="#eee" fill-opacity="0" r="21.8231723987879" stroke="#ea0" stroke-width="2" /><circle cx="430.78831758434035" cy="179.8166052191519" fill="#ea0" r="2.827892086263464" stroke="#ea0" stroke-width="2" /><circle cx="452.58130125271924" cy="180.96408784515882" fill="#eee" fill-opacity="0" r="37.812297120687795" stroke="#eee" stroke-width="2" /><circle cx="472.57653937753463" cy="213.0570818761791" fill="#eee" r="2.6102231928654778" stroke="#eee" stroke-width="2" /><circle cx="452.58130125271924" cy="180.96408784515882" fill="#eee" fill-opacity="0" r="55.938220307034" stroke="#eee" stroke-width="2" /><circle cx="506.1669380410402" cy="197.01600427617765" fill="#eee" r="3.252701491079807" stroke="#eee" stroke-width="2" /><circle cx="338.3400040874068" cy="208.34132172072512" fill="#eee" r="4.603865384638267" stroke="#eee" stroke-width="2" /><circle cx="338.3400040874068" cy="208.34132172072512" fill="#eee" fill-opacity="0" r="20.00878719559634" stroke="#eee" stroke-width="2" /><circle cx="329.11968037233845" cy="190.58358550160054" fill="#eee" r="2.132876938772122" stroke="#eee" stroke-width="2" /><circle cx="338.3400040874068" cy="208.34132172072512" fill="#eee" fill-opacity="0" r="39.144105385654704" stroke="#eee" stroke-width="2" /><circle cx="301.84139133159863" cy="222.48742554279568" fill="#eee" r="2.3674072974299003" stroke="#eee" stroke-width="2" /></svg>

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8" ?>
<svg baseProfile="full" height="100%" version="1.1" width="100%" xmlns="http://www.w3.org/2000/svg" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"><![CDATA[.background { fill: #222; }]]></style></defs><rect class="background" height="100%" width="100%" x="0" y="0" /><line stroke="#eee" stroke-width="2" x1="94.01202243435863" x2="51.628773919897476" y1="60.79150855767895" y2="135.3977536212687" /><line stroke="#eee" stroke-width="2" x1="51.628773919897476" x2="264.4887607719297" y1="135.3977536212687" y2="235.11308787395214" /><line stroke="#eee" stroke-width="2" x1="264.4887607719297" x2="226.29065062635962" y1="235.11308787395214" y2="90.48204392257941" /><line stroke="#eee" stroke-width="2" x1="226.29065062635962" x2="169.1700020437034" y1="90.48204392257941" y2="104.17066086036256" /><circle cx="94.01202243435863" cy="60.79150855767895" fill="#eee" r="5.53091646215765" stroke="#eee" stroke-width="2" /><circle cx="51.628773919897476" cy="135.3977536212687" fill="#eee" r="6.358738772326545" stroke="#eee" stroke-width="2" /><circle cx="264.4887607719297" cy="235.11308787395214" fill="#0ae" r="9.400253756805997" stroke="#0ae" stroke-width="2" /><circle cx="226.29065062635962" cy="90.48204392257941" fill="#eee" r="6.236611100792434" stroke="#eee" stroke-width="2" /><circle cx="169.1700020437034" cy="104.17066086036256" fill="#eee" r="9.41158619939395" stroke="#eee" stroke-width="2" /></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

25
installer/ED_LRR.iss Normal file
View File

@ -0,0 +1,25 @@
[Setup]
AppName = "ED_LRR"
AppVersion ="0.1.0"
; WizardStyle = modern
DefaultDirName = {autopf}\ED_LRR
DefaultGroupName=ED_LRR
Compression = lzma2/ultra
SolidCompression = true
InternalCompressLevel = ultra
OutputBaseFilename="ED_LRR Setup"
ChangesEnvironment = true
[Files]
Source: "..\exe\__main__.dist\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs
[Icons]
Name: "{group}\ED_LRR"; Filename: "{app}\ED_LRR.exe"; WorkingDir: "{app}"
Name: "{group}\Uninstall ED_LRR"; Filename: "{uninstallexe}"
[Tasks]
;Name: modifypath; Description: Add application directory to PATH; Flags: unchecked
[Run]
Filename: "{app}\ED_LRR.exe"; Parameters: "download"; StatusMsg: "Downloading EDSM dumps..."; Description: "Download EDSM dumps"; Flags: postinstall
Filename: "{app}\ED_LRR.exe"; Description: "Launch ED_LRR"; Flags: postinstall nowait skipifsilent unchecked

2
pyproject.toml Normal file
View File

@ -0,0 +1,2 @@
[build-system]
requires = ["setuptools", "wheel", "setuptools-rust"]

2
pytest.ini Normal file
View File

@ -0,0 +1,2 @@
[pytest]
qt_api=pyqt5

2
rust/.cargo/config Normal file
View File

@ -0,0 +1,2 @@
[build]
rustflags = ["-C", "target-cpu=native"]

533
rust/Cargo.lock generated Normal file
View File

@ -0,0 +1,533 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "aho-corasick"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "autocfg"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bincode"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "block-buffer"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "block-padding"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bstr"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "byte-tools"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "byteorder"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "csv"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "csv-core"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ctor"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "digest"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ed_lrr"
version = "0.0.0"
dependencies = [
"bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"permutohedron 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"pyo3 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rstar 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.41 (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)",
]
[[package]]
name = "either"
version = "1.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "fnv"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "generic-array"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ghost"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "humantime"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "indoc"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"indoc-impl 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "indoc-impl"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"unindent 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "inventory"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ctor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
"ghost 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"inventory-impl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "inventory-impl"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "itertools"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "itoa"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "keccak"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.2.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "memchr"
version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-traits"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "opaque-debug"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "paste"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"paste-impl 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "paste-impl"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "pdqselect"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "permutohedron"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "proc-macro-hack"
version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "proc-macro2"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "pyo3"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"indoc 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"inventory 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"paste 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"pyo3cls 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
"spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"unindent 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "pyo3-derive-backend"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "pyo3cls"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"pyo3-derive-backend 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "quick-error"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "quote"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex"
version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex-automata"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex-syntax"
version = "0.6.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rstar"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"pdqselect 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ryu"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde"
version = "1.0.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_derive"
version = "1.0.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_json"
version = "1.0.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "sha3"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
"byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "spin"
version = "0.5.2"
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 = "syn"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "thread_local"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "typenum"
version = "1.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-xid"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unindent"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "version_check"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d"
"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
"checksum bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8ab639324e3ee8774d296864fbc0dbbb256cf1a41c490b94cba90c082915f92"
"checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"
"checksum block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4dc3af3ee2e12f3e5d224e5e1e3d73668abbeb69e566d361f7d5563a4fdf09"
"checksum bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8d6c2c5b58ab920a4f5aeaaca34b4488074e8cc7596af94e6f8c6ff247c60245"
"checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
"checksum csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37519ccdfd73a75821cac9319d4fce15a81b9fcf75f951df5b9988aa3a0af87d"
"checksum csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9b5cadb6b25c77aeff80ba701712494213f4a8418fcda2ee11b6560c3ad0bf4c"
"checksum ctor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd8ce37ad4184ab2ce004c33bf6379185d3b1c95801cab51026bd271bf68eedc"
"checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
"checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"
"checksum ghost 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2a36606a68532b5640dc86bb1f33c64b45c4682aad4c50f3937b317ea387f3d6"
"checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
"checksum indoc 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3f9553c1e16c114b8b77ebeb329e5f2876eed62a8d51178c8bc6bff0d65f98f8"
"checksum indoc-impl 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b714fc08d0961716390977cdff1536234415ac37b509e34e5a983def8340fb75"
"checksum inventory 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f4cece20baea71d9f3435e7bbe9adf4765f091c5fe404975f844006964a71299"
"checksum inventory-impl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c2869bf972e998977b1cb87e60df70341d48e48dca0823f534feb91ea44adaf9"
"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358"
"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
"checksum keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7"
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
"checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8"
"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e"
"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32"
"checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
"checksum paste 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "423a519e1c6e828f1e73b720f9d9ed2fa643dce8a7737fb43235ce0b41eeaa49"
"checksum paste-impl 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4214c9e912ef61bf42b81ba9a47e8aad1b2ffaf739ab162bf96d1e011f54e6c5"
"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 proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)" = "ecd45702f76d6d3c75a80564378ae228a85f0b59d2f3ed43c91b4a69eb2ebfc5"
"checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27"
"checksum pyo3 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a00f96312ebe4082db7d93ad062df1818f597660002541c1bbae6752ec583244"
"checksum pyo3-derive-backend 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1a7caa60cb986fca5b488e29d078fb25ae228e01dab080b855168ce061bbef0a"
"checksum pyo3cls 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a5ccfa624ed9b5d805079f1ad64b3f1de5d551a946d4cf494f1f032b5572d39f"
"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
"checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd"
"checksum regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "92b73c2a1770c255c240eaa4ee600df1704a38dc3feaa6e949e7fcd4f8dc09f9"
"checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716"
"checksum rstar 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08c3cf91d6318ed050a8dda79bc857665f9c3d41524b6f70bbd0396c5d9d662d"
"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8"
"checksum serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "9796c9b7ba2ffe7a9ce53c2287dfc48080f4b2b362fcc245a259b3a7201119dd"
"checksum serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "4b133a43a1ecd55d4086bd5b4dc6c1751c68b1bfbeba7a5040442022c7e7c02e"
"checksum serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "2f72eb2a68a7dc3f9a691bfda9305a1c017a6215e5a4545c258500d2099a37c2"
"checksum sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd26bc0e7a2e3a7c959bc494caf58b72ee0c71d67704e9520f736ca7e4853ecf"
"checksum spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
"checksum strsim 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "032c03039aae92b350aad2e3779c352e104d919cb192ba2fabbd7b831ce4f0f6"
"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf"
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
"checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9"
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
"checksum unindent 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "63f18aa3b0e35fed5a0048f029558b1518095ffe2a0a31fb87c93dece93a4993"
"checksum version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce"

26
rust/Cargo.toml Normal file
View File

@ -0,0 +1,26 @@
[package]
name = "ed_lrr"
version = "0.0.0"
authors = ["Daniel Seiller <earthnuker@gmail.com>"]
edition = "2018"
repository = "https://gitlab.com/Earthnuker/ed_lrr.git"
license = "WTFPL"
[lib]
crate-type = ["cdylib"]
name = "_ed_lrr"
[dependencies]
pyo3 = { version = "0.8.0", features = ["extension-module"] }
csv = "1.1.1"
serde = { version = "1.0.101", features = ["derive"] }
humantime = "1.3.0"
permutohedron = "0.2.4"
serde_json = "1.0.40"
fnv = "1.0.6"
bincode = "1.2.0"
sha3 = "0.8.2"
byteorder = "1.3.2"
strsim = "0.9.2"
rstar = "0.5.1"

View File

@ -1,4 +1,6 @@
use serde::{Deserialize, Serialize};
use std::cmp::Ordering;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SystemSerde {
pub id: u32,
@ -36,3 +38,15 @@ pub struct System {
pub distance: u32,
pub pos: [f32; 3],
}
impl Ord for System {
fn cmp(&self, other: &Self) -> Ordering {
self.id.cmp(&other.id)
}
}
impl PartialOrd for System {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}

192
rust/src/lib.rs Normal file
View File

@ -0,0 +1,192 @@
extern crate strsim;
mod common;
mod preprocess;
mod route;
use common::{System, SystemSerde};
use pyo3::exceptions::*;
use pyo3::prelude::*;
use pyo3::types::{PyDict, PyList};
use std::collections::HashMap;
use std::path::PathBuf;
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()))
}
});
}
}
Ok(best)
}
#[pymodule]
pub fn _ed_lrr(_py: Python, m: &PyModule) -> PyResult<()> {
/// preprocess(infile_systems, infile_bodies, outfile, callback)
/// --
///
/// Preprocess bodies.json and systemsWithCoordinates.json into stars.csv
#[pyfn(m, "preprocess")]
fn ed_lrr_preprocess(
py: Python<'static>,
infile_systems: String,
infile_bodies: String,
outfile: String,
callback: PyObject,
) -> PyResult<PyObject> {
use preprocess::*;
let state = PyDict::new(py);
let state_dict = PyDict::new(py);
callback.call(py, (state_dict,), None).unwrap();
let callback_wrapped = move |state: &PreprocessState| {
// println!("SEND: {:?}",state);
state_dict.set_item("file", state.file.clone())?;
state_dict.set_item("total", state.total)?;
state_dict.set_item("count", state.count)?;
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),
&callback_wrapped,
)
.unwrap();
Ok(state.to_object(py))
}
///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))?;
}
}
Ok(ret.to_object(py))
}
Err(e) => Err(PyErr::new::<ValueError, _>(e)),
}
}
/// route(infile, hops, range, radius_mult, mode,primary, greedyness, precomp, callback)
/// --
///
/// Compute a Route using the suplied parameters
#[pyfn(m, "route")]
#[allow(clippy::too_many_arguments)]
fn route(
py: Python<'static>,
hops: Vec<String>,
range: f32,
prune: Option<(usize, f32)>,
mode: String,
primary: bool,
permute: bool,
keep_first: bool,
keep_last: bool,
greedyness: Option<f32>,
precomp: Option<String>,
path: String,
callback: PyObject,
) -> PyResult<PyObject> {
use route::*;
let mode = match Mode::parse(&mode) {
Ok(val) => val,
Err(e) => {
return Err(PyErr::new::<ValueError, _>(e));
}
};
let state_dict = PyDict::new(py);
callback.call(py, (state_dict,), None).unwrap();
let callback_wrapped = move |state: &SearchState| {
state_dict.set_item("mode", state.mode.clone())?;
state_dict.set_item("system", state.system.clone())?;
state_dict.set_item("body", state.body.clone())?;
state_dict.set_item("depth", state.depth)?;
state_dict.set_item("queue_size", state.queue_size)?;
state_dict.set_item("d_rem", state.d_rem)?;
state_dict.set_item("d_total", state.d_total)?;
state_dict.set_item("prc_done", state.prc_done)?;
state_dict.set_item("n_seen", state.n_seen)?;
state_dict.set_item("prc_seen", state.prc_seen)?;
state_dict.set_item("from", state.from.clone())?;
state_dict.set_item("to", state.to.clone())?;
callback.call(py, (state_dict,), None)
};
let mut systems = Vec::new();
for sys in hops {
systems.push(route::SysEntry::parse(&sys))
}
let opts = RouteOpts {
systems,
range: Some(range),
file_path: PathBuf::from(path),
precomp_file: precomp.map(PathBuf::from),
callback: Box::new(callback_wrapped),
mode,
factor: greedyness,
precompute: false,
permute,
keep_first,
keep_last,
primary,
prune,
};
let none = ().to_object(py);
match route(opts) {
Ok(Some(route)) => {
let hops = route.iter().map(|hop| {
let pos = PyList::new(py, hop.pos.iter());
let elem = PyDict::new(py);
elem.set_item("star_type", hop.star_type.clone()).unwrap();
elem.set_item("system", hop.system.clone()).unwrap();
elem.set_item("body", hop.body.clone()).unwrap();
elem.set_item("distance", hop.distance).unwrap();
elem.set_item("pos", pos).unwrap();
elem
});
let lst = PyList::new(py, hops);
Ok(lst.to_object(py))
}
Ok(None) => Ok(none),
Err(e) => Err(PyErr::new::<ValueError, _>(e)),
}
}
Ok(())
}

206
rust/src/preprocess.rs Normal file
View File

@ -0,0 +1,206 @@
use crate::common::SystemSerde;
use fnv::FnvHashMap;
use pyo3::prelude::*;
use serde::Deserialize;
use serde_json::Result;
use std::fs::File;
use std::io::Seek;
use std::io::{BufRead, BufReader, BufWriter, SeekFrom};
use std::path::PathBuf;
use std::str;
use std::time::Instant;
#[derive(Debug, Deserialize)]
#[allow(non_snake_case)]
struct Body {
name: String,
subType: String,
#[serde(rename = "type")]
body_type: String,
systemId: i32,
systemId64: i64,
#[serde(rename = "distanceToArrival")]
distance: u32,
}
#[derive(Debug, Deserialize)]
struct Coords {
x: f32,
y: f32,
z: f32,
}
#[derive(Debug, Deserialize)]
struct System {
id: i32,
id64: i64,
name: String,
coords: Coords,
date: String,
}
#[derive(Debug)]
pub struct PreprocessState {
pub file: String,
pub message: String,
pub total: u64,
pub done: u64,
pub count: usize,
}
fn get_mult(star_type: &str) -> f32 {
if star_type.contains("White Dwarf") {
return 1.5;
}
if star_type.contains("Neutron") {
return 4.0;
}
1.0
}
fn process(
path: &PathBuf,
func: &mut dyn for<'r> FnMut(&'r str) -> (),
callback: &dyn Fn(&PreprocessState) -> PyResult<PyObject>,
) -> std::io::Result<()> {
let mut buffer = String::new();
let fh = File::open(path)?;
let total_size = fh.metadata()?.len();
let mut t_last = Instant::now();
let mut reader = BufReader::new(fh);
let mut state = PreprocessState {
file: path.to_str().unwrap().to_owned(),
total: total_size,
done: 0,
count: 0,
message: format!("Processing {} ...", path.to_str().unwrap()),
};
println!("Loading {} ...", path.to_str().unwrap());
while let Ok(n) = reader.read_line(&mut buffer) {
if n == 0 {
break;
}
buffer = buffer.trim_end().trim_end_matches(|c| c == ',').to_string();
if !buffer.is_empty() {
func(&buffer);
}
let pos = reader.seek(SeekFrom::Current(0)).unwrap();
state.done = pos;
state.count += 1;
if t_last.elapsed().as_millis() > 100 {
callback(&state)?;
t_last = Instant::now();
}
buffer.clear();
}
Ok(())
}
fn process_systems(
path: &PathBuf,
callback: &dyn Fn(&PreprocessState) -> PyResult<PyObject>,
) -> FnvHashMap<i32, System> {
let mut ret = FnvHashMap::default();
process(
path,
&mut |line| {
let sys_res: Result<System> = serde_json::from_str(&line);
if let Ok(sys) = sys_res {
ret.insert(sys.id, sys);
} else {
eprintln!("\nError parsing: {}\n\t{:?}\n", line, sys_res.unwrap_err());
}
},
callback,
)
.unwrap();
ret
}
fn build_index(path: &PathBuf) -> std::io::Result<()> {
let mut wtr = BufWriter::new(File::create(path.with_extension("idx"))?);
let mut idx: Vec<u64> = Vec::new();
let mut records = (csv::Reader::from_path(path)?).into_deserialize::<SystemSerde>();
loop {
idx.push(records.reader().position().byte());
if records.next().is_none() {
break;
}
}
bincode::serialize_into(&mut wtr, &idx).unwrap();
Ok(())
}
fn process_bodies(
path: &PathBuf,
out_path: &PathBuf,
systems: &mut FnvHashMap<i32, System>,
callback: &dyn Fn(&PreprocessState) -> PyResult<PyObject>,
) -> std::io::Result<()> {
println!(
"Processing {} into {} ...",
path.to_str().unwrap(),
out_path.to_str().unwrap(),
);
let mut n: u32 = 0;
let mut wtr = csv::Writer::from_path(out_path)?;
process(
path,
&mut |line| {
if !line.contains("Star") {
return;
}
let body_res: Result<Body> = serde_json::from_str(&line);
if let Ok(body) = body_res {
if !body.body_type.contains("Star") {
return;
}
if let Some(sys) = systems.get(&body.systemId) {
let sub_type = body.subType;
let mult = get_mult(&sub_type);
let sys_name = sys.name.clone();
let rec = SystemSerde {
id: n,
star_type: sub_type,
system: sys_name,
body: body.name,
mult,
distance: body.distance,
x: sys.coords.x,
y: sys.coords.y,
z: sys.coords.z,
};
wtr.serialize(rec).unwrap();
n += 1;
};
} else {
eprintln!("\nError parsing: {}\n\t{:?}\n", line, body_res.unwrap_err());
}
},
callback,
)
.unwrap();
println!("Total Systems: {}", n);
systems.clear();
Ok(())
}
pub fn preprocess_files(
bodies: &PathBuf,
systems: &PathBuf,
out_path: &PathBuf,
callback: &dyn Fn(&PreprocessState) -> PyResult<PyObject>,
) -> std::io::Result<()> {
if !out_path.exists() {
let mut systems = process_systems(systems, &callback);
process_bodies(bodies, out_path, &mut systems, &callback)?;
} else {
println!(
"File '{}' exists, not overwriting it",
out_path.to_str().unwrap()
);
}
println!("Building index...");
println!("Index result: {:?}", build_index(&out_path));
Ok(())
}

File diff suppressed because it is too large Load Diff

76
setup.py Normal file
View File

@ -0,0 +1,76 @@
import sys
import distutils.cmd
import distutils.log
from setuptools import find_packages, setup
from setuptools_rust import Binding, RustExtension, Strip
with open("README.md", "r") as fh:
long_description = fh.read()
setup(
name="ed_lrr_gui",
version_format="{tag}.dev{commitcount}+{gitsha}",
author="Daniel Seiller",
author_email="earthnuker@gmail.com",
description="Elite: Dangerous long range route plotter",
long_description=long_description,
long_description_content_type="text/markdown",
url="none yet",
rust_extensions=[
RustExtension(
"_ed_lrr",
path="rust/Cargo.toml",
binding=Binding.PyO3,
strip=Strip.No,
debug=False,
native=True,
)
],
packages=find_packages(),
entry_points={"console_scripts": ["ed_lrr = ed_lrr_gui.__main__:main"]},
install_requires=[
"appdirs",
"PyYAML",
"requests",
"python-dateutil",
"pyperclip",
"click",
"tqdm",
"PyQt5",
"click-default-group",
"profig",
"colorama",
"svgwrite",
],
setup_requires=[
"setuptools",
"setuptools-rust",
"wheel",
"pyinstaller",
"pytest-runner",
"setuptools-git-version",
],
tests_require=["pytest", "pytest-pep8", "pytest-cov"],
extras_require={
"dev": ["black", "pyinstaller", "jinja2", "tsp"],
"web": [
"flask",
"sqlalchemy",
"webargs",
"flask-sqlalchemy",
"sqlalchemy-utils",
],
},
classifiers=[
"License :: OSI Approved :: MIT License",
"Programming Language :: Rust",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: Implementation :: CPython",
"Operating System :: OS Independent",
],
include_package_data=True,
zip_safe=False,
)

View File

@ -1,3 +0,0 @@
pub mod common;
pub mod preprocess;
pub mod route;

View File

@ -1,28 +0,0 @@
use ed_lrr::preprocess::{preprocess_files, PreprocessOpts};
use ed_lrr::route::{route, RouteOpts};
use humantime::format_duration;
use std::time::Instant;
use structopt::StructOpt;
#[derive(Debug, StructOpt)]
#[structopt(
name = "ed_lrr",
about = "Elite: Dangerous Long-Range Router",
rename_all = "snake_case"
)]
enum Opts {
/// Plots a route through multiple systems
Route(RouteOpts),
/// Preprocess EDSM Dump
Preprocess(PreprocessOpts),
}
fn main() -> std::io::Result<()> {
let t_start = Instant::now();
let opts = Opts::from_args();
let ret = match opts {
Opts::Route(opts) => route(opts),
Opts::Preprocess(opts) => preprocess_files(opts),
};
println!("Total time: {}", format_duration(t_start.elapsed()));
ret
}

View File

@ -1,220 +0,0 @@
use crate::common::SystemSerde;
use fnv::FnvHashMap;
use humantime::format_duration;
use indicatif::{ProgressBar, ProgressStyle};
use serde::Deserialize;
use serde_json::Result;
use std::fs::File;
use std::io::Seek;
use std::io::{BufRead, BufReader, BufWriter, SeekFrom};
use std::path::PathBuf;
use std::str;
use std::time::Instant;
use structopt::StructOpt;
#[derive(Debug, StructOpt)]
pub struct PreprocessOpts {
#[structopt(short, long = "bodies")]
/// Path to bodies.json
pub bodies: PathBuf,
#[structopt(short, long = "systems")]
/// Path to systemsWithCoordinates.json
pub systems: PathBuf,
#[structopt(default_value = "stars")]
/// outfile prefix
pub prefix: String,
}
#[derive(Debug, Deserialize)]
#[allow(non_snake_case)]
struct Body {
name: String,
subType: String,
#[serde(rename = "type")]
body_type: String,
systemId: i32,
systemId64: i64,
#[serde(rename = "distanceToArrival")]
distance: u32,
}
#[derive(Debug, Deserialize)]
struct Coords {
x: f32,
y: f32,
z: f32,
}
#[derive(Debug, Deserialize)]
struct System {
id: i32,
id64: i64,
name: String,
coords: Coords,
date: String,
}
#[derive(Debug, StructOpt)]
#[structopt(
name = "ed_lrr_pp",
about = "Preprocessor for Elite: Dangerous Long-Range Router",
rename_all = "snake_case"
)]
/// Preprocess data for ed_lrr
struct Opt {
#[structopt(short, long = "bodies")]
/// Path to bodies.json
bodies: PathBuf,
#[structopt(short, long = "systems")]
/// Path to systemsWithCoordinates.json
systems: PathBuf,
#[structopt(default_value = "stars")]
/// outfile prefix
prefix: String,
}
fn get_mult(star_type: &str) -> f32 {
if star_type.contains("White Dwarf") {
return 1.5;
}
if star_type.contains("Neutron") {
return 4.0;
}
1.0
}
fn process(path: &PathBuf, func: &mut dyn for<'r> FnMut(&'r str) -> ()) -> std::io::Result<()> {
let mut cnt = 0;
let mut buffer = String::new();
let t_start = Instant::now();
let fh = File::open(path)?;
let prog_bar = ProgressBar::new(fh.metadata()?.len());
prog_bar.set_style(
ProgressStyle::default_bar()
.template(
"[{elapsed_precise}/{eta_precise}]{spinner} [{wide_bar}] {binary_bytes}/{binary_total_bytes} ({percent}%)",
)
.progress_chars("#9876543210 ")
.tick_chars("/-\\|"),
);
prog_bar.set_draw_delta(1024 * 1024);
let mut reader = BufReader::new(fh);
println!("Loading {} ...", path.to_str().unwrap());
while let Ok(n) = reader.read_line(&mut buffer) {
if n == 0 {
break;
}
buffer = buffer.trim_end().trim_end_matches(|c| c == ',').to_string();
if !buffer.is_empty() {
func(&buffer);
}
prog_bar.set_position(reader.seek(SeekFrom::Current(0)).unwrap());
cnt += 1;
buffer.clear();
}
prog_bar.finish_and_clear();
println!(
"Processed {} lines in {} ...",
cnt,
format_duration(t_start.elapsed())
);
Ok(())
}
fn process_systems(path: &PathBuf) -> FnvHashMap<i64, System> {
let mut ret = FnvHashMap::default();
process(path, &mut |line| {
let sys_res: Result<System> = serde_json::from_str(&line);
if let Ok(sys) = sys_res {
ret.insert(sys.id64, sys);
} else {
eprintln!("\nError parsing: {}\n\t{:?}\n", line, sys_res.unwrap_err());
}
})
.unwrap();
ret
}
fn build_index(path: &PathBuf) -> std::io::Result<()> {
let mut wtr = BufWriter::new(File::create(path.with_extension("idx"))?);
let mut idx: Vec<u64> = Vec::new();
let mut records = (csv::Reader::from_path(path)?).into_deserialize::<SystemSerde>();
loop {
idx.push(records.reader().position().byte());
if records.next().is_none() {
break;
}
}
bincode::serialize_into(&mut wtr, &idx).unwrap();
Ok(())
}
fn process_bodies(
path: &PathBuf,
out_prefix: &str,
systems: &mut FnvHashMap<i64, System>,
) -> std::io::Result<()> {
let out_path = PathBuf::from(format!("{}.csv", out_prefix));
println!(
"Processing {} into {} ...",
path.to_str().unwrap(),
out_path.to_str().unwrap(),
);
let mut n: u32 = 0;
let mut wtr = csv::Writer::from_path(out_path)?;
process(path, &mut |line| {
if !line.contains("Star") {
return;
}
let body_res: Result<Body> = serde_json::from_str(&line);
if let Ok(body) = body_res {
if !body.body_type.contains("Star") {
return;
}
if let Some(sys) = systems.get(&body.systemId64) {
let sub_type = body.subType;
let mult = get_mult(&sub_type);
let sys_name = sys.name.clone();
let mut body_name = body.name.replace(&sys_name, "").trim().to_string();
if body_name == sys_name {
body_name = "".to_string();
}
let rec = SystemSerde {
id: n,
star_type: sub_type,
system: sys_name,
body: body_name,
mult,
distance: body.distance,
x: sys.coords.x,
y: sys.coords.y,
z: sys.coords.z,
};
wtr.serialize(rec).unwrap();
n += 1;
};
} else {
eprintln!("\nError parsing: {}\n\t{:?}\n", line, body_res.unwrap_err());
}
})
.unwrap();
println!("Total Systems: {}", n);
systems.clear();
Ok(())
}
pub fn preprocess_files(opts: PreprocessOpts) -> std::io::Result<()> {
let out_path = PathBuf::from(format!("{}.csv", &opts.prefix));
if !out_path.exists() {
let mut systems = process_systems(&opts.systems);
process_bodies(&opts.bodies, &opts.prefix, &mut systems)?;
} else {
println!(
"File '{}' exists, not overwriting it",
out_path.to_str().unwrap()
);
}
println!("Building index...");
println!("Index result: {:?}", build_index(&out_path));
Ok(())
}

34
tox.ini Normal file
View File

@ -0,0 +1,34 @@
[tox]
envlist = py35,py36,py37
requires = tox-conda
[testenv]
description = Build ED_LRR
recreate = True
skip_install = True
skipsdist = True
deps =
PyQt5
setuptools_rust
conda_deps =
pycrypto
nuitka
passenv =
CARGO_HOME
RUSTUP_HOME
INCLUDE
LIB
MSSdk
DISTUTILS_USE_SDK
whitelist_externals =
cargo
iscc
cmd
conda_channels =
conda-forge
commands =
python build_gui.py
pip install .
python -m nuitka --plugin-enable=multiprocessing --remove-output --plugin-enable=qt-plugins --standalone --assume-yes-for-downloads --follow-imports --output-dir=exe ed_lrr_gui\__main__.py
cmd /c rename exe\__main__.dist\__main__.exe ED_LRR.exe
iscc /F"ED_LRR_{envname}" /Qp installer/ED_LRR.iss