Compare commits

...

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

28 changed files with 700 additions and 2203 deletions

18
.gitignore vendored
View File

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

26
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,26 @@
# 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

View File

@ -8,6 +8,14 @@ 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"
@ -83,6 +91,20 @@ 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"
@ -121,7 +143,7 @@ dependencies = [
[[package]]
name = "csv"
version = "1.1.1"
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)",
@ -139,15 +161,6 @@ dependencies = [
"memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ctor"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"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 = "digest"
version = "0.8.0"
@ -162,16 +175,17 @@ 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.1 (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)",
"pyo3 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rstar 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.40 (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]]
@ -203,13 +217,11 @@ dependencies = [
]
[[package]]
name = "ghost"
version = "0.1.0"
name = "heck"
version = "0.3.1"
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)",
"unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -232,26 +244,6 @@ dependencies = [
"regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "inventory"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ctor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
"ghost 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"inventory-impl 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "inventory-impl"
version = "0.1.3"
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 = "itertools"
version = "0.8.0"
@ -288,24 +280,6 @@ dependencies = [
"scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "mashup"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"mashup-impl 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro-hack 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "mashup-impl"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro-hack 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "memchr"
version = "2.2.0"
@ -375,19 +349,6 @@ name = "permutohedron"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "proc-macro-hack"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro-hack-impl 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "proc-macro-hack-impl"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "proc-macro2"
version = "0.4.30"
@ -396,42 +357,6 @@ dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "pyo3"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"inventory 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"mashup 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"pyo3cls 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "pyo3-derive-backend"
version = "0.7.0"
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 = "pyo3cls"
version = "0.7.0"
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)",
"pyo3-derive-backend 0.7.0 (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 = "quick-error"
version = "1.2.2"
@ -598,6 +523,7 @@ 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]]
@ -608,6 +534,11 @@ 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"
@ -636,12 +567,12 @@ name = "serde"
version = "1.0.94"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde_derive 1.0.95 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_derive"
version = "1.0.95"
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)",
@ -651,11 +582,11 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.40"
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 1.0.0 (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)",
]
@ -677,10 +608,30 @@ version = "0.6.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "spin"
version = "0.5.0"
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"
@ -710,6 +661,14 @@ 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"
@ -728,6 +687,11 @@ 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"
@ -744,8 +708,8 @@ version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "version_check"
version = "0.1.5"
name = "vec_map"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -769,6 +733,7 @@ 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"
@ -779,31 +744,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"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.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37519ccdfd73a75821cac9319d4fce15a81b9fcf75f951df5b9988aa3a0af87d"
"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 ctor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3b4c17619643c1252b5f690084b82639dd7fac141c57c8e77a00e0148132092c"
"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 ghost 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5297b71943dc9fea26a3241b178c140ee215798b7f79f7773fd61683e25bca74"
"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 inventory 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "21df85981fe094480bc2267723d3dc0fd1ae0d1f136affc659b7398be615d922"
"checksum inventory-impl 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8a877ae8bce77402d5e9ed870730939e097aad827b2a932b361958fa9d6e75aa"
"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 mashup 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f2d82b34c7fb11bb41719465c060589e291d505ca4735ea30016a91f6fc79c3b"
"checksum mashup-impl 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "aa607bfb674b4efb310512527d64266b065de3f894fc52f84efcbf7eaa5965fb"
"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"
@ -813,12 +774,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum parking_lot_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb88cb1cb3790baa6776844f968fea3be44956cf184fa1be5a03341f5491278c"
"checksum 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.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c725b36c99df7af7bf9324e9c999b9e37d92c8f8caf106d82e1d7953218d2d8"
"checksum proc-macro-hack-impl 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2b753ad9ed99dd8efeaa7d2fb8453c8f6bc3e54b97966d35f1bc77ca6865254a"
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
"checksum pyo3 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d09e6e2d3fa5ae1a8af694f865e03e763e730768b16e3097851ff0b7f2276086"
"checksum pyo3-derive-backend 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9d7ae8ab3017515cd7c82d88ce49b55e12a56c602dc69993e123da45c91b186"
"checksum pyo3cls 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c494f8161f5b73096cc50f00fbb90fe670f476cde5e59c1decff39b546d54f40"
"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"
@ -839,26 +795,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"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.95 (registry+https://github.com/rust-lang/crates.io-index)" = "5ea8eb91549d859275aef70c58bb30bd62ce50e5eb1a52d32b1b6886e02f7bce"
"checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704"
"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 spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55"
"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 version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
"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

@ -7,25 +7,20 @@ repository = "https://gitlab.com/Earthnuker/ed_lrr.git"
license = "WTFPL"
[lib]
crate-type = ["cdylib"]
[profile.release]
debug=true
# debug=true
[dependencies]
csv = "1.1.1"
serde = { version = "1.0", features = ["derive"] }
rstar = "0.4.0"
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.40"
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"
[dependencies.pyo3]
version = "0.7.0"
features = ["extension-module"]

View File

@ -1,2 +0,0 @@
include rust/Cargo.toml
recursive-include rust/src *

View File

@ -1,41 +1,20 @@
# Testing
```bash
conda create -n ed_lrr_gui_env python=3
conda activate ed_lrr_gui_env
python build_gui.py
pip install -e .
rs_gui_test
```
# Building
```bash
conda create -n ed_lrr_gui_env python=3
conda activate ed_lrr_gui_env
python build_gui.py
pip install setuptools_rust
pip install .
python setup.py build
python setup.py bdist_wheel
python setup.py sdist
mkdir exe
cd exe
pyinstaller --noupx --name ed_lrr_gui ../ed_lrr_gui/__main__.py
pyinstaller --noupx --onefile --name ed_lrr_gui ../ed_lrr_gui/__main__.py
cd ..
```
# Clean
```bash
rm -rfv _*.pyd *.pyc *.egg-info pip-wheel-metadata dist exe build __pycache__
cd rust
cargo clean
cargo clean --release
cd ..
```
# TODO
- integrate callbacks into the GUI: WIP
- QTimer pulls from queue updates UI (every 100ms)
# 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

View File

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

View File

@ -1,5 +0,0 @@
rm -rfv _*.pyd *.egg-info pip-wheel-metadata dist exe build __pycache__
cd rust
cargo clean
cargo clean --release
cd ..

180
dumps/process.py Normal file
View File

@ -0,0 +1,180 @@
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)

2
dumps/urls.txt Normal file
View File

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

View File

@ -1,2 +0,0 @@
from _ed_lrr import *
from . import gui

View File

@ -1,357 +0,0 @@
import sys
import os
import requests as RQ
from datetime import datetime, timedelta
from PyQt5.QtCore import QThread, pyqtSignal, Qt
from PyQt5.QtWidgets import (
QMainWindow,
QApplication,
QFileDialog,
QProgressDialog,
QTreeWidgetItem,
)
from urllib.request import Request, urlopen
import gzip
from PyQt5.QtGui import QPalette, QColor
import ed_lrr_gui
import ed_lrr_gui.config as cfg
from ed_lrr_gui.gui.ed_lrr import Ui_ED_LRR
import multiprocessing as MP
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 ProgressDialog(QProgressDialog):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setWindowModality(Qt.WindowModal)
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):
jobs = [
(self.systems_url, self.systems_file),
(self.bodies_url, self.bodies_file),
]
for url, dest in 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.set_pallete()
def set_pallete(self):
colors = {
"Window": QColor(53, 53, 53),
"WindowText": Qt.white,
"Base": QColor(15, 15, 15),
"AlternateBase": QColor(53, 53, 53),
"ToolTipBase": Qt.white,
"ToolTipText": Qt.white,
"Text": Qt.white,
"Button": QColor(53, 53, 53),
"ButtonText": Qt.white,
"BrightText": Qt.red,
"Highlight": QColor(255, 128, 0),
"HighlightedText": Qt.black,
}
palette = QPalette()
for entry, color in colors.items():
palette.setColor(getattr(QPalette, entry), color)
if color == Qt.darkGray:
palette.setColor(
QPalette.Disabled, getattr(QPalette, entry), QColor(53, 53, 53)
)
else:
palette.setColor(
QPalette.Disabled, getattr(QPalette, entry), Qt.darkGray
)
self.setPalette(palette)
class ED_LRR(Ui_ED_LRR):
dl_thread = None
diag_prog = None
dl_started = None
def __init__(self):
super().__init__()
self.config = cfg.load()
def get_open_file(self, filetypes, callback=None):
fileName, _ = QFileDialog.getOpenFileName(
self.main_window,
"Open file",
str(cfg.data_dir),
filetypes,
options=QFileDialog.DontUseNativeDialog,
)
if callback:
return callback(fileName)
return fileName
def get_save_file(self, filetypes, callback=None):
fileName, _ = QFileDialog.getSaveFileName(
self.main_window,
"Save file",
str(cfg.data_dir),
filetypes,
options=QFileDialog.DontUseNativeDialog,
)
if callback:
return callback(fileName)
return fileName
def set_sys_lst(self, path):
if path not in self.config.history_out_path:
self.config.history_out_path.append(path)
self.inp_sys_lst.addItem(path)
self.inp_out_pp.addItem(path)
def set_bodies_file(self, path):
if path not in self.config.history_bodies_path:
self.config.history_bodies_path.append(path)
self.inp_bodies_pp.addItem(path)
def set_systems_file(self, path):
if path not in self.config.history_systems_path:
self.config.history_systems_path.append(path)
self.inp_systems_pp.addItem(path)
def update_dropdowns(self):
return
def log(self, *args):
t = datetime.today()
msg_t = "[{}] {}".format(t, str.format(*args))
self.txt_log.append(msg_t)
def set_comp_mode(self, _):
if self.rd_comp.isChecked():
comp_mode = "Compute Route"
self.btn_add.setText("Search+Add")
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.btn_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")
self.log("ROUTE_MODE", mode)
def set_greedyness(self, value):
self.lbl_greedyness.setText("Greedyness Factor ({:.0%})".format(value / 100))
def sys_to_dict(self, n):
header = [
self.lst_sys.headerItem().data(c, 0)
for c in range(self.lst_sys.headerItem().columnCount())
]
system = [
self.lst_sys.topLevelItem(n).data(c, 0)
for c in range(self.lst_sys.topLevelItem(n).columnCount())
]
return dict(zip(header, system))
def run(self):
settings = {}
settings["permute"] = (
self.chk_permute_keep_first.checkState(),
self.chk_permute_keep_last.checkState(),
)
settings["range"] = self.sb_range.value()
settings["systems"] = [
self.sys_to_dict(i) for i in range(self.lst_sys.topLevelItemCount())
]
print(settings)
progress = ProgressDialog(
"(Not actually computing)", "Cancel", 0, 0, self.main_window
)
progress.setWindowTitle("Computing Route")
progress.setFixedSize(400, 100)
progress.setRange(0, 0)
progress.show()
def add_system(self):
n = self.lst_sys.topLevelItemCount() + 1
name = self.inp_sys.text()
item = QTreeWidgetItem(
self.lst_sys, [str(n) + ". Name: " + name, "Type: " + name[::-1]]
)
item.sys_id = "SYS_ID_HERE"
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_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_progress)
self.dl_thread.start()
print(".")
def setup_signals(self):
self.btn_download.clicked.connect(self.run_download)
self.inp_systems_dest_dl.setCurrentText(r"D:\devel\rust\ed_lrr_gui\DL\s.json")
self.inp_bodies_dest_dl.setCurrentText(r"D:\devel\rust\ed_lrr_gui\DL\b.json")
self.set_greedyness(self.sld_greedyness.value())
self.cmb_mode.currentTextChanged.connect(self.set_route_mode)
self.rd_comp.toggled.connect(self.set_comp_mode)
self.rd_precomp.toggled.connect(self.set_comp_mode)
self.sld_greedyness.valueChanged.connect(self.set_greedyness)
self.btn_go.clicked.connect(self.run)
self.btn_add.clicked.connect(self.add_system)
self.btn_rm.clicked.connect(self.remove_system)
self.btn_out_browse_pp.clicked.connect(
lambda: self.get_save_file("CSV File (*.csv)", self.set_sys_lst)
)
self.btn_sys_lst_browse.clicked.connect(
lambda: self.get_open_file("CSV File (*.csv)", self.set_sys_lst)
)
self.btn_bodies_browse_pp.clicked.connect(
lambda: self.get_open_file("JSON File (*.json)", self.set_bodies_file)
)
self.btn_bodies_dest_browse_dl.clicked.connect(
lambda: self.get_save_file("JSON File (*.json)", self.set_bodies_file)
)
self.btn_systems_browse_pp.clicked.connect(
lambda: self.get_open_file("JSON File (*.json)", self.set_systems_file)
)
self.btn_systems_dest_browse_dl.clicked.connect(
lambda: self.get_save_file("JSON File (*.json)", self.set_systems_file)
)
def handle_close(self):
cfg.write(self.config)
print("BYEEEEEE!")
def setupUi(self, MainWindow, app):
super().setupUi(MainWindow)
self.update_dropdowns()
self.main_window = MainWindow
self.app = app
self.setup_signals()
self.lst_sys.setHeaderLabels(["Name", "Type"])
self.set_route_mode()
def main():
app = App()
MainWindow = QMainWindow()
ui = ED_LRR()
ui.setupUi(MainWindow, app)
MainWindow.show()
ret = app.exec_()
ui.handle_close()
exit(ret)
if __name__ == "__main__":
MP.freeze_support()
main()

View File

@ -1,45 +0,0 @@
import pathlib
import appdirs
import yaml
from collections import namedtuple
config_dir = pathlib.Path(appdirs.user_config_dir("ED_LRR"))
config_dir.mkdir(parents=True, exist_ok=True)
config_file = config_dir / "config.yml"
config_file.touch()
data_dir = pathlib.Path(appdirs.user_data_dir("ED_LRR"))
data_dir.mkdir(parents=True, exist_ok=True)
def make_config():
return {
"history_bodies_url": [],
"history_systems_url": [],
"history_bodies_path": [],
"history_systems_path": [],
"history_out_path": [],
"range": None,
"primary": False,
"mode": "bfs",
"greedyness": 0.5,
}
def write(cfg):
with config_file.open("w", encoding="utf-8") as of:
yaml.dump(cfg._asdict(), of, default_flow_style=False)
def load():
data = yaml.load(config_file.open(encoding="utf-8"), Loader=yaml.Loader)
if data is None:
data = make_config()
write(data)
return namedtuple("Config", data)(**data)
# print("CFG:", yaml.load_config())
# print(config_file, data_dir)
# exit(1)

View File

@ -1,383 +0,0 @@
# -*- 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.0
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_ED_LRR(object):
def setupUi(self, ED_LRR):
ED_LRR.setObjectName("ED_LRR")
ED_LRR.setEnabled(True)
ED_LRR.resize(577, 500)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(ED_LRR.sizePolicy().hasHeightForWidth())
ED_LRR.setSizePolicy(sizePolicy)
ED_LRR.setMinimumSize(QtCore.QSize(577, 500))
ED_LRR.setMaximumSize(QtCore.QSize(577, 500))
ED_LRR.setStyleSheet("")
ED_LRR.setDocumentMode(False)
ED_LRR.setTabShape(QtWidgets.QTabWidget.Rounded)
self.centralwidget = QtWidgets.QWidget(ED_LRR)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName("verticalLayout")
self.tabs = QtWidgets.QTabWidget(self.centralwidget)
self.tabs.setEnabled(True)
self.tabs.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(True)
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(True)
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(True)
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(True)
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(True)
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(True)
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.btn_permute = QtWidgets.QPushButton(self.tab_route)
self.btn_permute.setObjectName("btn_permute")
self.formLayout_2.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.btn_permute)
self.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, "1")
self.formLayout_2.setWidget(7, QtWidgets.QFormLayout.SpanningRole, self.lst_sys)
self.sb_range = QtWidgets.QDoubleSpinBox(self.tab_route)
self.sb_range.setObjectName("sb_range")
self.formLayout_2.setWidget(8, QtWidgets.QFormLayout.FieldRole, self.sb_range)
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.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.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, 2, 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, 1, 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, 0, 1, 1)
self.formLayout_2.setLayout(4, QtWidgets.QFormLayout.FieldRole, self.gridLayout_4)
self.tabs.addTab(self.tab_route, "")
self.tab_log = QtWidgets.QWidget()
self.tab_log.setObjectName("tab_log")
self.gridLayout_3 = QtWidgets.QGridLayout(self.tab_log)
self.gridLayout_3.setObjectName("gridLayout_3")
self.txt_log = QtWidgets.QTextEdit(self.tab_log)
self.txt_log.setEnabled(True)
self.txt_log.setFrameShadow(QtWidgets.QFrame.Sunken)
self.txt_log.setLineWidth(1)
self.txt_log.setReadOnly(True)
self.txt_log.setAcceptRichText(False)
self.txt_log.setObjectName("txt_log")
self.gridLayout_3.addWidget(self.txt_log, 0, 0, 1, 1)
self.tabs.addTab(self.tab_log, "")
self.verticalLayout.addWidget(self.tabs)
ED_LRR.setCentralWidget(self.centralwidget)
self.menu = QtWidgets.QMenuBar(ED_LRR)
self.menu.setGeometry(QtCore.QRect(0, 0, 577, 21))
self.menu.setObjectName("menu")
self.menu_file = QtWidgets.QMenu(self.menu)
self.menu_file.setObjectName("menu_file")
ED_LRR.setMenuBar(self.menu)
self.bar_status = QtWidgets.QStatusBar(ED_LRR)
self.bar_status.setObjectName("bar_status")
ED_LRR.setStatusBar(self.bar_status)
self.menu_act_quit = QtWidgets.QAction(ED_LRR)
self.menu_act_quit.setObjectName("menu_act_quit")
self.menu_file.addAction(self.menu_act_quit)
self.menu.addAction(self.menu_file.menuAction())
self.retranslateUi(ED_LRR)
self.tabs.setCurrentIndex(2)
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", "Search+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.btn_permute.setText(_translate("ED_LRR", "Permute"))
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.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.tabs.setTabText(self.tabs.indexOf(self.tab_route), _translate("ED_LRR", "Route"))
self.tabs.setTabText(self.tabs.indexOf(self.tab_log), _translate("ED_LRR", "Log"))
self.menu_file.setTitle(_translate("ED_LRR", "File"))
self.menu_act_quit.setText(_translate("ED_LRR", "Quit"))
self.menu_act_quit.setShortcut(_translate("ED_LRR", "Ctrl+Q"))

View File

@ -1,674 +0,0 @@
<?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">
<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>true</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>true</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>true</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>true</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>true</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>true</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>Search+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="QPushButton" name="btn_permute">
<property name="text">
<string>Permute</string>
</property>
</widget>
</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>
<column>
<property name="text">
<string notr="true">1</string>
</property>
</column>
</widget>
</item>
<item row="8" column="1">
<widget class="QDoubleSpinBox" name="sb_range"/>
</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="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>
<item row="4" column="1">
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="2">
<widget class="QCheckBox" name="chk_permute_keep_last">
<property name="text">
<string>Last</string>
</property>
</widget>
</item>
<item row="0" column="1">
<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="0">
<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>
</layout>
</widget>
<widget class="QWidget" name="tab_log">
<attribute name="title">
<string>Log</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QTextEdit" name="txt_log">
<property name="enabled">
<bool>true</bool>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<property name="lineWidth">
<number>1</number>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
<property name="acceptRichText">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menu">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>577</width>
<height>21</height>
</rect>
</property>
<widget class="QMenu" name="menu_file">
<property name="title">
<string>File</string>
</property>
<addaction name="menu_act_quit"/>
</widget>
<addaction name="menu_file"/>
</widget>
<widget class="QStatusBar" name="bar_status"/>
<action name="menu_act_quit">
<property name="text">
<string>Quit</string>
</property>
<property name="shortcut">
<string>Ctrl+Q</string>
</property>
</action>
</widget>
<tabstops>
<tabstop>rd_comp</tabstop>
<tabstop>cmb_mode</tabstop>
<tabstop>chk_primary</tabstop>
<tabstop>sld_greedyness</tabstop>
<tabstop>rd_precomp</tabstop>
</tabstops>
<resources/>
<connections>
<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>

View File

@ -1,45 +0,0 @@
from multiprocessing import Process, Queue, freeze_support
import queue
from datetime import datetime, timedelta
import _ed_lrr
from collections import namedtuple
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
self.start()
def __iter__(self):
while self.is_alive():
try:
self.state.update(self.queue.get(True, 0.5))
yield self.state
except queue.Empty:
pass
while not self.queue.empty():
self.state.update(self.queue.get(True, 0.5))
yield self.state
def callback(self, state):
self.queue.put({"status": state})
def run(self):
_ed_lrr.preprocess(*self.args, **self.kwargs)
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)

View File

@ -1,51 +0,0 @@
from multiprocessing import Process, Queue, freeze_support
import queue
from datetime import datetime, timedelta
import _ed_lrr
from collections import namedtuple
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
self.start()
def __iter__(self):
while self.is_alive():
try:
self.state.update(self.queue.get(True, 0.5))
yield self.state
except queue.Empty:
pass
while not self.queue.empty():
self.state.update(self.queue.get(True, 0.5))
yield self.state
def callback(self, state):
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

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

View File

@ -1,131 +0,0 @@
mod common;
mod preprocess;
mod route;
use pyo3::prelude::*;
use pyo3::types::{PyDict,PyList};
use pyo3::exceptions::*;
use std::path::PathBuf;
#[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("done",state.done)?;
callback.call(py,(state_dict,),None)
};
preprocess_files(&PathBuf::from(infile_bodies), &PathBuf::from(infile_systems), &PathBuf::from(outfile), Box::new(callback_wrapped)).unwrap();
return Ok(state.to_object(py));
}
/// route(infile, hops, range, mode,primary, greedyness, precomp, callback)
/// --
///
/// Compute a Route using the suplied parameters
#[pyfn(m, "route")]
fn route(
py: Python<'static>,
hops: Vec<String>,
range: f32,
mode: String,
primary: bool,
permute: bool,
greedyness: Option<f32>,
precomp: Option<String>,
path: String,
callback: PyObject,
) -> PyResult<PyObject> {
use route::*;
// TODO: Verify Parameters
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| {
println!("SEND: {:?}",state);
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)?;
callback.call(py,(state_dict,),None)
};
let opts=RouteOpts{
systems:hops,
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: permute,
keep_first: true,
keep_last: true,
primary
};
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();
return elem;
});
let lst=PyList::new(py,hops);
return Ok(lst.to_object(py));
}
Ok(None) => {
return Ok(none);
},
Err(e) => {
return Err(PyErr::new::<ValueError,_>(e));
}
};
/*
let state = PyDict::new(py);
state.set_item("infile", infile)?;
state.set_item("source", source)?;
state.set_item("dest", dest)?;
state.set_item("range", range)?;
state.set_item("mode", mode)?;
state.set_item("greedyness", greedyness)?;
state.set_item("precomp", precomp)?;
state.set_item("callback", callback)?;
return callback.call(py,(state.to_object(py),),None);
*/
}
Ok(())
}

View File

@ -1,24 +0,0 @@
from setuptools import setup
from setuptools_rust import Binding, RustExtension, Strip
setup(
name="ed_lrr_gui",
version="0.1.0",
author="Daniel Seiller",
author_email="earthnuker@gmail.com",
url="none yet",
rust_extensions=[
RustExtension(
"_ed_lrr",
path="rust/Cargo.toml",
binding=Binding.PyO3,
strip=Strip.All,
native=True,
)
],
packages=["ed_lrr_gui"],
entry_points={"console_scripts": ["ed_lrr_gui=ed_lrr_gui.__main__:main"]},
install_requires=["PyQt5", "appdirs", "PyYAML", "requests", "python-dateutil"],
include_package_data=True,
zip_safe=False,
)

View File

@ -1,5 +1,4 @@
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SystemSerde {
pub id: u32,

3
src/lib.rs Normal file
View File

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

28
src/main.rs Normal file
View File

@ -0,0 +1,28 @@
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,14 +1,29 @@
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::time::Instant;
use std::str;
use pyo3::prelude::*;
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)]
@ -39,15 +54,25 @@ struct System {
date: String,
}
#[derive(Debug)]
pub struct PreprocessState {
pub file: String,
pub total: u64,
pub done: u64,
pub count: usize,
#[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;
@ -58,18 +83,22 @@ fn get_mult(star_type: &str) -> f32 {
1.0
}
fn process(path: &PathBuf, func: &mut dyn for<'r> FnMut(&'r str) -> (),callback: &Box<dyn Fn(&PreprocessState) -> PyResult<PyObject>>) -> std::io::Result<()> {
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 total_size= fh.metadata()?.len();
let mut t_last=Instant::now();
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);
let mut state=PreprocessState {
file: path.to_str().unwrap().to_owned(),
total: total_size,
done: 0,
count: 0
};
println!("Loading {} ...", path.to_str().unwrap());
while let Ok(n) = reader.read_line(&mut buffer) {
if n == 0 {
@ -79,28 +108,29 @@ fn process(path: &PathBuf, func: &mut dyn for<'r> FnMut(&'r str) -> (),callback:
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();
}
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,callback: &Box<dyn Fn(&PreprocessState) -> PyResult<PyObject>> ) -> FnvHashMap<i32, System> {
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.id, sys);
ret.insert(sys.id64, sys);
} else {
eprintln!("\nError parsing: {}\n\t{:?}\n", line, sys_res.unwrap_err());
}
},callback)
})
.unwrap();
ret
}
@ -121,10 +151,10 @@ fn build_index(path: &PathBuf) -> std::io::Result<()> {
fn process_bodies(
path: &PathBuf,
out_path: &PathBuf,
systems: &mut FnvHashMap<i32, System>,
callback: &Box<dyn Fn(&PreprocessState) -> PyResult<PyObject>>,
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(),
@ -141,15 +171,19 @@ fn process_bodies(
if !body.body_type.contains("Star") {
return;
}
if let Some(sys) = systems.get(&body.systemId) {
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,
body: body_name,
mult,
distance: body.distance,
x: sys.coords.x,
@ -162,17 +196,18 @@ fn process_bodies(
} 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: Box<dyn Fn(&PreprocessState) -> PyResult<PyObject>>) -> std::io::Result<()> {
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(systems,&callback);
process_bodies(bodies, out_path, &mut systems,&callback)?;
let mut systems = process_systems(&opts.systems);
process_bodies(&opts.bodies, &opts.prefix, &mut systems)?;
} else {
println!(
"File '{}' exists, not overwriting it",

View File

@ -11,38 +11,80 @@ use std::hash::{Hash, Hasher};
use std::io::Seek;
use std::io::{BufRead, BufReader, BufWriter, Write};
use std::path::PathBuf;
use std::str::FromStr;
use std::time::Instant;
use pyo3::prelude::*;
use structopt::StructOpt;
use crate::common::{System, SystemSerde};
#[derive(Debug)]
pub struct SearchState {
pub mode: String,
pub system: String,
pub body: String,
pub depth: usize,
pub queue_size: usize,
pub d_rem: f32,
pub d_total: f32,
pub prc_done: f32,
pub n_seen: usize,
pub prc_seen: f32
}
#[derive(Debug, StructOpt)]
pub struct RouteOpts {
#[structopt(short, long = "range")]
/// Jump Range
pub range: Option<f32>,
#[structopt(
parse(from_os_str),
short = "i",
long = "path",
default_value = "./stars.csv"
)]
/// Path to stars.csv
///
/// Generate using ed_lrr_pp
pub file_path: PathBuf,
#[structopt(
parse(from_os_str),
long = "precomp_file",
conflicts_with = "precompute"
)]
/// Path to precomputed route graph
///
/// Generate using --precompute option
pub precomp_file: Option<PathBuf>,
#[structopt(
short = "c",
long = "precompute",
conflicts_with = "full_permute",
conflicts_with = "permute",
conflicts_with = "precomp_file"
)]
/// Precompute all routes for the specified jump range starting at the specified system and write the result to {system}_{range}.bin
pub precompute: bool,
#[structopt(short = "p", long = "permute", conflicts_with = "full_permute")]
/// Permute intermediate hops to find shortest route
pub permute: bool,
#[structopt(short = "o", long = "primary")]
/// Only route through the primary star of a system
pub primary: bool,
pub keep_first: bool,
pub keep_last: bool,
#[structopt(short = "f", long = "full_permute", conflicts_with = "permute")]
/// Permute all hops to find shortest route
pub full_permute: bool,
#[structopt(short = "g", long = "factor")]
/// Greedyness factor for A-Star (0=BFS, inf=Greedy)
pub factor: Option<f32>,
#[structopt(
short,
long,
raw(possible_values = "&[\"bfs\", \"greedy\",\"astar\"]"),
default_value = "bfs"
)]
/// Search mode
///
/**
- BFS is guaranteed to find the shortest route but very slow
- Greedy is a lot faster but will probably not find the shortest route
- A-Star is a good middle ground between speed and accuracy
*/
pub mode: Mode,
/// Systems to route through
pub systems: Vec<String>,
pub callback: Box<dyn Fn(&SearchState) -> PyResult<PyObject>>
}
#[derive(Debug)]
@ -52,10 +94,10 @@ pub enum Mode {
AStar,
}
impl Mode {
pub fn parse(s: &str) -> Result<Mode, String> {
let s=s.to_lowercase();
match s.as_ref() {
impl FromStr for Mode {
type Err = String;
fn from_str(s: &str) -> Result<Mode, String> {
match s {
"bfs" => Ok(Mode::BFS),
"greedy" => Ok(Mode::Greedy),
"astar" => Ok(Mode::AStar),
@ -138,18 +180,24 @@ struct LineCache {
}
impl LineCache {
pub fn new(path: &PathBuf) -> Option<Self> {
pub fn new(path: &PathBuf) -> std::io::Result<Self> {
let idx_path = path.with_extension("idx");
let cache =
bincode::deserialize_from(&mut BufReader::new(File::open(idx_path).ok()?)).ok()?;
let mut reader = BufReader::new(File::open(path).ok()?);
let t_load = Instant::now();
println!("Loading {}", path.to_str().unwrap());
let mut idx_reader = BufReader::new(File::open(idx_path)?);
let cache = match bincode::deserialize_from(&mut idx_reader) {
Ok(value) => value,
err => err.unwrap(),
};
let mut reader = BufReader::new(File::open(path)?);
let header = Self::read_record(&mut reader);
let ret = Self {
file: reader,
cache,
header,
};
Some(ret)
println!("Done in {}!", format_duration(t_load.elapsed()));
Ok(ret)
}
fn read_record(reader: &mut BufReader<File>) -> Option<StringRecord> {
let mut line = String::new();
@ -175,18 +223,18 @@ pub struct Router {
range: f32,
primary_only: bool,
path: PathBuf,
callback: Box<dyn Fn(&SearchState) -> PyResult<PyObject>>
}
impl Router {
pub fn new(path: &PathBuf, range: f32, primary_only: bool,callback: Box<dyn Fn(&SearchState) -> PyResult<PyObject>>) -> Result<Self,String> {
pub fn new(path: &PathBuf, range: f32, primary_only: bool) -> Self {
let mut scoopable = FnvHashSet::default();
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 mut reader = csv::ReaderBuilder::new()
.from_path(path)
.unwrap_or_else(|e| {
println!("Error opening {}: {}", path.to_str().unwrap(), e);
std::process::exit(1);
});
let t_load = Instant::now();
println!("Loading {}...", path.to_str().unwrap());
let systems: Vec<System> = reader
.deserialize::<SystemSerde>()
@ -212,21 +260,28 @@ impl Router {
sys.build()
})
.collect();
println!("Building RTree...");
let ret = Self {
tree: RTree::bulk_load(systems),
scoopable,
route_tree: None,
range,
primary_only,
cache: LineCache::new(path),
cache: LineCache::new(path).ok(),
path: path.clone(),
callback: callback,
};
Ok(ret)
println!(
"{} Systems loaded in {}",
ret.tree.size(),
format_duration(t_load.elapsed())
);
ret
}
pub fn from_file(filename: &PathBuf,callback: Box<dyn Fn(&SearchState) -> PyResult<PyObject>>) -> Result<(PathBuf, Self),String> {
pub fn from_file(filename: &PathBuf) -> (PathBuf, Self) {
let t_load = Instant::now();
let mut reader = BufReader::new(File::open(&filename).unwrap());
println!("Loading {}", filename.to_str().unwrap());
let (primary, range, file_hash, path, route_tree): (
bool,
f32,
@ -235,11 +290,12 @@ impl Router {
FnvHashMap<u32, u32>,
) = bincode::deserialize_from(&mut reader).unwrap();
let path = PathBuf::from(path);
println!("Done in {}!", format_duration(t_load.elapsed()));
if hash_file(&path) != file_hash {
return Err("File hash mismatch!".to_string());
panic!("File hash mismatch!")
}
let cache = LineCache::new(&path);
Ok((
let cache = LineCache::new(&path).ok();
(
path.clone(),
Self {
tree: RTree::default(),
@ -249,9 +305,8 @@ impl Router {
cache,
primary_only: primary,
path,
callback
},
))
)
}
fn closest(&self, point: &[f32; 3]) -> &System {
@ -273,34 +328,34 @@ impl Router {
&self,
waypoints: &[String],
range: f32,
keep: (bool,bool),
full: bool,
mode: Mode,
factor: f32,
) -> Result<Vec<System>,String> {
) -> Vec<System> {
let mut best_score: f32 = std::f32::MAX;
let mut waypoints = waypoints.to_owned();
let mut best_permutation_waypoints = waypoints.to_owned();
let first = waypoints.first().cloned();
let last = waypoints.last().cloned();
let t_start = Instant::now();
println!("Finding best permutation of hops...");
while waypoints.prev_permutation() {}
loop {
let c_first = waypoints.first().cloned();
let c_last = waypoints.last().cloned();
let valid = (keep.0 && (c_first == first)) && (keep.1 && (c_last==last));
if valid {
if full || ((c_first == first) && (c_last == last)) {
let mut total_d = 0.0;
for pair in waypoints.windows(2) {
match pair {
[src, dst] => {
let (mut src, dst) =
(self.name_to_systems(&src)?, self.name_to_systems(&dst)?);
(self.name_to_systems(&src), self.name_to_systems(&dst));
src.sort_by_key(|&p| (p.mult * 10.0) as u8);
let src = src.last().unwrap();
let dst = dst.last().unwrap();
total_d += src.distp2(dst);
}
_ => return Err("Invalid routing parameters!".to_string()),
_ => panic!("Invalid routing parameters!"),
}
}
if total_d < best_score {
@ -312,6 +367,8 @@ impl Router {
break;
}
}
println!("Done in {}!", format_duration(t_start.elapsed()));
println!("Best permutation: {:?}", best_permutation_waypoints);
self.name_multiroute(&best_permutation_waypoints, range, mode, factor)
}
@ -322,10 +379,10 @@ impl Router {
range: f32,
mode: Mode,
factor: f32,
) -> Result<Vec<System>,String> {
) -> Vec<System> {
let mut coords = Vec::new();
for p_name in waypoints {
let mut p_l = self.name_to_systems(p_name)?;
let mut p_l = self.name_to_systems(p_name);
p_l.sort_by_key(|&p| (p.mult * 10.0) as u8);
let p = p_l.last().unwrap();
coords.push((p_name, p.pos));
@ -338,15 +395,15 @@ impl Router {
range: f32,
mode: Mode,
factor: f32,
) -> Result<Vec<System>,String> {
) -> Vec<System> {
let mut route: Vec<System> = Vec::new();
for pair in waypoints.windows(2) {
match *pair {
[src, dst] => {
let block = match mode {
Mode::BFS => self.route_bfs(&src, &dst, range)?,
Mode::Greedy => self.route_greedy(&src, &dst, range)?,
Mode::AStar => self.route_astar(&src, &dst, range, factor)?,
Mode::BFS => self.route_bfs(&src, &dst, range),
Mode::Greedy => self.route_greedy(&src, &dst, range),
Mode::AStar => self.route_astar(&src, &dst, range, factor),
};
if route.is_empty() {
for sys in block.iter() {
@ -358,19 +415,20 @@ impl Router {
}
}
}
_ => return Err("Invalid routing parameters!".to_string()),
_ => panic!("Invalid routing parameters!"),
}
}
Ok(route)
route
}
fn name_to_systems(&self, name: &str) -> Result<Vec<&System>,String> {
fn name_to_systems(&self, name: &str) -> Vec<&System> {
for sys in &self.tree {
if sys.system == name {
return Ok(self.neighbours(&sys, 0.0).collect());
return self.neighbours(&sys, 0.0).collect();
}
}
Err(format!("System not found: \"{}\"", name))
eprintln!("System not found: \"{}\"", name);
std::process::exit(1);
}
pub fn route_astar(
@ -379,33 +437,29 @@ impl Router {
dst: &(&String, [f32; 3]),
range: f32,
factor: f32,
) -> Result<Vec<System>,String> {
) -> Vec<System> {
if factor == 0.0 {
return self.route_bfs(src, dst, range);
}
println!("Running A-Star with greedy factor of {}", factor);
let (src_name, src) = src;
let (dst_name, dst) = dst;
let start_sys = self.closest(src);
let goal_sys = self.closest(dst);
let d_total = dist(&start_sys.pos,&goal_sys.pos);
let mut d_rem=d_total;
let mut state=SearchState {
mode:"A-Star".into(),
depth:0,
queue_size:0,
d_rem: d_total,
d_total: d_total,
prc_done: 0.0,
n_seen:0,
prc_seen: 0.0,
body: start_sys.body.clone(),
system: start_sys.system.clone()
};
{
let d = dist(src, dst);
println!("Plotting route from {} to {}...", src_name, dst_name);
println!(
"Jump Range: {} Ly, Distance: {} Ly, Theoretical Jumps: {}",
range,
d,
d / range
);
}
let total = self.tree.size() as f32;
let t_start = Instant::now();
let mut prev = FnvHashMap::default();
let mut seen = FnvHashSet::default();
let t_start = Instant::now();
let mut found = false;
let mut maxd = 0;
let mut queue: Vec<(usize, usize, &System)> = Vec::new();
@ -415,24 +469,11 @@ impl Router {
&start_sys,
));
seen.insert(start_sys.id);
while !(queue.is_empty() || found) {
while let Some((depth, _, sys)) = queue.pop() {
if (depth+1) > maxd {
maxd = depth+1;
state.depth=depth;
state.queue_size=queue.len();
state.prc_done=((d_total-d_rem)*100f32) / d_total;
state.d_rem=d_rem;
state.n_seen=seen.len();
state.prc_seen=((seen.len()*100) as f32) / total;
state.body=sys.body.clone();
state.system=sys.system.clone();
match (self.callback)(&state) {
Ok(_) => (),
Err(e) => {
return Err(format!("{:?}",e).to_string());
}
};
if depth > maxd {
maxd = depth;
print!(
"[{}] Depth: {}, Queue: {}, Seen: {} ({:.02}%) \r",
format_duration(t_start.elapsed()),
@ -454,10 +495,6 @@ impl Router {
.map(|nb| {
prev.insert(nb.id, sys);
let d_g = (nb.distp(goal_sys) / range) as usize;
let dist = dist(&nb.pos, &goal_sys.pos);
if dist < d_rem {
d_rem = dist;
}
(depth + 1, d_g, nb)
}),
);
@ -475,7 +512,8 @@ impl Router {
println!();
if !found {
return Err(format!("No route from {} to {} found!", src_name, dst_name).to_string());
eprintln!("No route from {} to {} found!", src_name, dst_name);
return Vec::new();
}
let mut v: Vec<System> = Vec::new();
let mut curr_sys = goal_sys;
@ -489,7 +527,7 @@ impl Router {
}
}
v.reverse();
Ok(v)
v
}
pub fn route_greedy(
@ -497,28 +535,26 @@ impl Router {
src: &(&String, [f32; 3]),
dst: &(&String, [f32; 3]),
range: f32,
) -> Result<Vec<System>,String> {
) -> Vec<System> {
println!("Running Greedy-Search");
let (src_name, src) = src;
let (dst_name, dst) = dst;
let start_sys = self.closest(src);
let goal_sys = self.closest(dst);
let d_total = dist(&start_sys.pos, &goal_sys.pos);
let mut d_rem=d_total;
let mut state=SearchState {
mode:"Greedy".into(),
depth:0,
queue_size:0,
d_rem: d_total,
d_total: d_total,
prc_done: 0.0,
n_seen:0,
prc_seen: 0.0,
body:start_sys.body.clone(),
system:start_sys.system.clone(),
};
{
let d = dist(src, dst);
println!("Plotting route from {} to {}...", src_name, dst_name);
println!(
"Jump Range: {} Ly, Distance: {} Ly, Theoretical Jumps: {}",
range,
d,
d / range
);
}
let total = self.tree.size() as f32;
let mut prev = FnvHashMap::default();
let mut seen = FnvHashSet::default();
let t_start = Instant::now();
let mut found = false;
let mut maxd = 0;
let mut queue: Vec<(f32, f32, usize, &System)> = Vec::new();
@ -526,22 +562,17 @@ impl Router {
seen.insert(start_sys.id);
while !(queue.is_empty() || found) {
while let Some((_, _, depth, sys)) = queue.pop() {
if (depth+1) > maxd {
state.depth=depth;
state.queue_size=queue.len();
state.prc_done=((d_total-d_rem)*100f32) / d_total;
state.d_rem=d_rem;
state.n_seen=seen.len();
state.prc_seen=((seen.len()*100) as f32) / total;
state.body=sys.body.clone();
state.system=sys.system.clone();
match (self.callback)(&state) {
Ok(_) => (),
Err(e) => {
return Err(format!("{:?}",e).to_string());
}
};
maxd = depth+1;
if depth > maxd {
maxd = depth;
print!(
"[{}] Depth: {}, Queue: {}, Seen: {} ({:.02}%) \r",
format_duration(t_start.elapsed()),
depth,
queue.len(),
seen.len(),
((seen.len() * 100) as f32) / total
);
std::io::stdout().flush().unwrap();
}
if sys.id == goal_sys.id {
found = true;
@ -553,10 +584,6 @@ impl Router {
.filter(|&nb| seen.insert(nb.id))
.map(|nb| {
prev.insert(nb.id, sys);
let dist = dist(&nb.pos, &goal_sys.pos);
if dist < d_rem {
d_rem = dist;
}
(-nb.mult, nb.distp2(goal_sys), depth + 1, nb)
}),
);
@ -564,8 +591,11 @@ impl Router {
queue.reverse();
}
}
println!();
println!();
if !found {
return Err(format!("No route from {} to {} found!", src_name, dst_name).to_string());
eprintln!("No route from {} to {} found!", src_name, dst_name);
return Vec::new();
}
let mut v: Vec<System> = Vec::new();
let mut curr_sys = goal_sys;
@ -579,17 +609,18 @@ impl Router {
}
}
v.reverse();
Ok(v)
v
}
pub fn precompute(&mut self, src: &str) -> Result<(),String> {
let mut sys_l = self.name_to_systems(src)?;
pub fn precompute(&mut self, src: &str) {
let mut sys_l = self.name_to_systems(src);
sys_l.sort_by_key(|&sys| (sys.mult * 10.0) as u8);
let sys = sys_l.last().unwrap();
println!("Precomputing routes starting at {} ...", sys.system);
let total = self.tree.size() as f32;
let t_start = Instant::now();
let mut prev = FnvHashMap::default();
let mut seen = FnvHashSet::default();
let t_start = Instant::now();
let mut depth = 0;
let mut queue: VecDeque<(usize, &System)> = VecDeque::new();
let mut queue_next: VecDeque<(usize, &System)> = VecDeque::new();
@ -626,7 +657,9 @@ impl Router {
self.range,
if self.primary_only { "_primary" } else { "" }
);
println!("\nSaving to {}", ofn);
let mut out_fh = BufWriter::new(File::create(&ofn).unwrap());
// (range, path, route_tree)
let data = (
self.primary_only,
self.range,
@ -634,13 +667,11 @@ impl Router {
String::from(self.path.to_str().unwrap()),
self.route_tree.as_ref().unwrap(),
);
return match bincode::serialize_into(&mut out_fh, &data) {
Ok(_) => Ok(()),
Err(e) => Err(format!("Error: {}",e).to_string())
};
bincode::serialize_into(&mut out_fh, &data).unwrap();
}
fn get_systems_by_ids(&mut self, path: &PathBuf, ids: &[u32]) -> Result<FnvHashMap<u32, System>,String> {
fn get_systems_by_ids(&mut self, path: &PathBuf, ids: &[u32]) -> FnvHashMap<u32, System> {
println!("Processing {}", path.to_str().unwrap());
let mut ret = FnvHashMap::default();
if let Some(c) = &mut self.cache.as_mut() {
let mut missing = false;
@ -650,22 +681,22 @@ impl Router {
ret.insert(*id, sys);
}
None => {
println!("ID {} not found in cache", id);
missing = true;
break;
}
}
}
if !missing {
return Ok(ret);
return ret;
}
}
let mut reader = match csv::ReaderBuilder::new()
.from_path(path) {
Ok(reader) => reader,
Err(e) => {
return Err(format!("Error opening {}: {}", path.to_str().unwrap(), e));
}
};
let mut reader = csv::ReaderBuilder::new()
.from_path(path)
.unwrap_or_else(|e| {
println!("Error opening {}: {}", path.to_str().unwrap(), e);
std::process::exit(1);
});
reader
.deserialize::<SystemSerde>()
.map(|res| res.unwrap())
@ -673,12 +704,15 @@ impl Router {
.map(|sys| {
ret.insert(sys.id, sys.build());
})
.count();
Ok(ret)
.last()
.unwrap_or_else(|| {
eprintln!("Error: No systems matching {:?} found!", ids);
std::process::exit(1);
});
ret
}
fn get_system_by_name(path: &PathBuf, name: &str) -> Result<System,String> {
// TODO: Fuzzy search (https://github.com/andylokandy/simsearch-rs)
fn get_system_by_name(path: &PathBuf, name: &str) -> System {
let mut reader = csv::ReaderBuilder::new()
.from_path(path)
.unwrap_or_else(|e| {
@ -688,18 +722,20 @@ impl Router {
let sys = reader
.deserialize::<SystemSerde>()
.map(|res| res.unwrap())
.find(|sys| sys.system == name);
match sys {
Some(system) => Ok(system.build()),
None => Err(format!("System {} not found!",name).to_string())
}
.find(|sys| sys.system == name)
.unwrap_or_else(|| {
eprintln!("Error: System '{}' not found!", name);
std::process::exit(1);
});
sys.build()
}
pub fn route_to(&mut self, dst: &str, systems_path: &PathBuf) -> Result<Vec<System>,String> {
pub fn route_to(&mut self, dst: &str, systems_path: &PathBuf) -> Vec<System> {
let prev = self.route_tree.as_ref().unwrap();
let dst = Self::get_system_by_name(&systems_path, dst)?;
let dst = Self::get_system_by_name(&systems_path, dst);
if !prev.contains_key(&dst.id) {
return Err(format!("System-ID {} not found", dst.id).to_string());
eprintln!("System-ID {} not found", dst.id);
std::process::exit(1);
};
let mut v_ids: Vec<u32> = Vec::new();
let mut v: Vec<System> = Vec::new();
@ -714,17 +750,12 @@ impl Router {
}
}
v_ids.reverse();
let id_map = self.get_systems_by_ids(&systems_path, &v_ids)?;
let id_map = self.get_systems_by_ids(&systems_path, &v_ids);
for sys_id in v_ids {
let sys = match id_map.get(&sys_id) {
Some(sys) => sys,
None => {
return Err(format!("System-ID {} not found!",sys_id));
}
};
let sys = id_map.get(&sys_id).unwrap();
v.push(sys.clone())
}
Ok(v)
v
}
pub fn route_bfs(
@ -732,62 +763,42 @@ impl Router {
src: &(&String, [f32; 3]),
dst: &(&String, [f32; 3]),
range: f32,
) -> Result<Vec<System>,String> {
) -> Vec<System> {
println!("Running BFS");
let (src_name, src) = src;
let (dst_name, dst) = dst;
let start_sys = self.closest(src);
let goal_sys = self.closest(dst);
let d_total = dist(&start_sys.pos, &goal_sys.pos);
let mut state=SearchState {
mode:"BFS".into(),
depth:0,
queue_size:0,
d_rem: d_total,
d_total: d_total,
prc_done: 0.0,
n_seen:0,
prc_seen: 0.0,
system: start_sys.system.clone(),
body: start_sys.body.clone()
};
{
let d = dist(src, dst);
println!("Plotting route from {} to {}...", src_name, dst_name);
println!(
"Jump Range: {} Ly, Distance: {} Ly, Estimated Jumps: {}",
"Jump Range: {} Ly, Distance: {} Ly, Theoretical Jumps: {}",
range,
d_total,
d_total / range
d,
d / range
);
}
let total = self.tree.size() as f32;
let mut prev = FnvHashMap::default();
let mut seen = FnvHashSet::default();
let t_start = Instant::now();
let mut depth = 0;
let mut found = false;
let mut queue: VecDeque<(usize, &System)> = VecDeque::new();
let mut queue_next: VecDeque<(usize, &System)> = VecDeque::new();
let mut d_rem = dist(&start_sys.pos, &goal_sys.pos);
queue.push_front((0, &start_sys));
seen.insert(start_sys.id);
while !(queue.is_empty() || found) {
state.depth=depth;
state.queue_size=queue.len();
state.prc_done=((d_total-d_rem)*100f32) / d_total;
state.d_rem=d_rem;
state.n_seen=seen.len();
state.prc_seen=((seen.len()*100) as f32) / total;
{
let s=queue.get(0).unwrap().1;
state.system=s.system.clone();
state.body=s.body.clone();
}
match (self.callback)(&state) {
Ok(_) => (),
Err(e) => {
return Err(format!("{:?}",e).to_string());
}
};
print!(
"[{}] Depth: {}, Queue: {}, Seen: {} ({:.02}%) \r",
format_duration(t_start.elapsed()),
depth,
queue.len(),
seen.len(),
((seen.len() * 100) as f32) / total
);
std::io::stdout().flush().unwrap();
while let Some((d, sys)) = queue.pop_front() {
if sys.id == goal_sys.id {
found = true;
@ -799,10 +810,6 @@ impl Router {
.filter(|&nb| seen.insert(nb.id))
.map(|nb| {
prev.insert(nb.id, sys);
let dist = dist(&nb.pos, &goal_sys.pos);
if dist < d_rem {
d_rem = dist;
}
(d + 1, nb)
}),
);
@ -813,7 +820,8 @@ impl Router {
println!();
println!();
if !found {
return Err(format!("No route from {} to {} found!", src_name, dst_name).to_string());
eprintln!("No route from {} to {} found!", src_name, dst_name);
return Vec::new();
}
let mut v: Vec<System> = Vec::new();
let mut curr_sys = goal_sys;
@ -827,57 +835,79 @@ impl Router {
}
}
v.reverse();
Ok(v)
v
}
}
pub fn route(opts: RouteOpts) -> Result<Option<Vec<System>>,String> {
pub fn route(opts: RouteOpts) -> std::io::Result<()> {
if opts.systems.is_empty() {
return if opts.precomp_file.is_some() {
Err("Error: Please specify exatly one system".to_string())
if opts.precomp_file.is_some() {
eprintln!("Error: Please specify exatly one system");
} else if opts.precompute {
Err("Error: Please specify at least one system".to_string())
eprintln!("Error: Please specify at least one system");
} else {
Err("Error: Please specify at least two systems".to_string())
eprintln!("Error: Please specify at least two systems");
}
std::process::exit(1);
}
let mut path = opts.file_path;
let mut router: Router = if opts.precomp_file.is_some() {
let (path_,ret) = Router::from_file(&opts.precomp_file.clone().unwrap(),Box::new(opts.callback))?;
path=path_;
ret
} else if opts.range.is_some() {
Router::new(&path, opts.range.unwrap(), opts.primary, Box::new(opts.callback))?
let ret = Router::from_file(&opts.precomp_file.clone().unwrap());
path = ret.0;
ret.1
} else {
return Err("Please specify a jump range!".to_string());
Router::new(&path, opts.range.unwrap(), opts.primary)
};
if opts.precompute {
for sys in opts.systems {
router.route_tree = None;
router.precompute(&sys)?;
router.precompute(&sys);
}
return Ok(None)
std::process::exit(0);
}
let t_route = Instant::now();
let route = if router.route_tree.is_some() {
router.route_to(opts.systems.first().unwrap(), &path)?
} else if opts.permute {
router.route_to(opts.systems.first().unwrap(), &path)
} else if opts.permute || opts.full_permute {
router.best_name_multiroute(
&opts.systems,
opts.range.unwrap(),
(opts.keep_first,opts.keep_last),
opts.full_permute,
opts.mode,
opts.factor.unwrap_or(1.0),
)?
)
} else {
router.name_multiroute(
&opts.systems,
opts.range.unwrap(),
opts.mode,
opts.factor.unwrap_or(1.0),
)?
)
};
println!("Route computed in {}\n", format_duration(t_route.elapsed()));
if route.is_empty() {
return Err("No route found!".to_string())
eprintln!("No route found!");
return Ok(());
}
return Ok(Some(route));
let mut total: f32 = 0.0;
for (sys1, sys2) in route.iter().zip(route.iter().skip(1)) {
let dist = sys1.distp(sys2);
total += dist;
println!(
"{} [{}] ({},{},{}) [{} Ls]: {:.2} Ly",
sys1.system,
sys1.star_type,
sys1.pos[0],
sys1.pos[1],
sys1.pos[2],
sys1.distance,
dist
);
}
let sys = route.iter().last().unwrap();
println!(
"{} [{}] ({},{},{}) [{} Ls]: {:.2} Ly",
sys.system, sys.star_type, sys.pos[0], sys.pos[1], sys.pos[2], sys.distance, 0.0
);
println!("Total: {:.2} Ly ({} Jumps)", total, route.len());
Ok(())
}

View File

@ -1 +0,0 @@
python build_gui.py && ed_lrr_gui