mirror of https://github.com/espruino/BangleApps
removing gpconv
parent
c98f6a9c71
commit
a73c38794a
|
@ -1,732 +0,0 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.58"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704"
|
||||
|
||||
[[package]]
|
||||
name = "assert_approx_eq"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c07dab4369547dbe5114677b33fbbf724971019f3818172d59a97a61c774ffd"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.65"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "11a17d453482a265fd5f8479f2a3f405566e6ca627837aaddb85af8b1ab8ef61"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||
|
||||
[[package]]
|
||||
name = "bzip2"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6afcd980b5f3a45017c57e57a2fcccbb351cc43a356ce117ef760ef8052b89b0"
|
||||
dependencies = [
|
||||
"bzip2-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bzip2-sys"
|
||||
version = "0.1.11+1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.73"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"time 0.1.44",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.12.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f2c43f534ea4b0b049015d00269734195e6d3f0f6635cb692251aca6f9f8b3c"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"darling_macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_core"
|
||||
version = "0.12.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e91455b86830a1c21799d94524df0845183fa55bafd9aa137b01c7d1065fa36"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"ident_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.12.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29b5acf0dea37a7f66f7b25d2c5e93fd46f8f6968b1a5d7a3e02e97768afc95a"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_builder"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d13202debe11181040ae9063d739fa32cfcaaebe2275fe387703460ae2365b30"
|
||||
dependencies = [
|
||||
"derive_builder_macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_builder_core"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "66e616858f6187ed828df7c64a6d71720d83767a7f19740b2d1b6fe6327b36e5"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_builder_macro"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58a94ace95092c5acb1e97a7e846b310cfbd499652f72297da7493f618a98d73"
|
||||
dependencies = [
|
||||
"derive_builder_core",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
|
||||
|
||||
[[package]]
|
||||
name = "error-chain"
|
||||
version = "0.12.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fallible-iterator"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
|
||||
|
||||
[[package]]
|
||||
name = "fallible-streaming-iterator"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "geo-types"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9805fbfcea97de816e6408e938603241879cc41eea3fba3f84f122f4f6f9c54"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.26.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4"
|
||||
|
||||
[[package]]
|
||||
name = "gpconv"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"gpx",
|
||||
"itertools",
|
||||
"lazy_static",
|
||||
"osmio",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gpx"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b03599b85866c88fd0125db7ca7a683be1550724918682c736c7893a399dc5e"
|
||||
dependencies = [
|
||||
"assert_approx_eq",
|
||||
"error-chain",
|
||||
"geo-types",
|
||||
"thiserror",
|
||||
"time 0.3.11",
|
||||
"xml-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashlink"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf"
|
||||
dependencies = [
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ident_case"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||
|
||||
[[package]]
|
||||
name = "iter-progress"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97059d64dd4e3a8e16696f6c0be50c1d5da3a709983f39b73fd7f84f120c5cd4"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.126"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
|
||||
|
||||
[[package]]
|
||||
name = "libsqlite3-sys"
|
||||
version = "0.22.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "290b64917f8b0cb885d9de0f9959fe1f775d7fa12f1da2db9001c1c8ab60f89d"
|
||||
dependencies = [
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc"
|
||||
dependencies = [
|
||||
"adler",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_threads"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.28.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1"
|
||||
|
||||
[[package]]
|
||||
name = "osmio"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0db40ae840afac7f6c710abf757bb76c6b95b4a34a20d55811ef70d30b3ea24f"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"byteorder",
|
||||
"bzip2",
|
||||
"chrono",
|
||||
"derive_builder",
|
||||
"flate2",
|
||||
"iter-progress",
|
||||
"protobuf",
|
||||
"quick-xml",
|
||||
"rusqlite",
|
||||
"separator",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"xml-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "protobuf"
|
||||
version = "2.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70731852eec72c56d11226c8a5f96ad5058a3dab73647ca5f7ee351e464f2571"
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.22.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8533f14c8382aaad0d592c812ac3b826162128b65662331e1127b45c3d18536b"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rusqlite"
|
||||
version = "0.25.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c4b1eaf239b47034fb450ee9cdedd7d0226571689d8823030c4b6c2cb407152"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"fallible-iterator",
|
||||
"fallible-streaming-iterator",
|
||||
"hashlink",
|
||||
"libsqlite3-sys",
|
||||
"memchr",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695"
|
||||
|
||||
[[package]]
|
||||
name = "separator"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f97841a747eef040fcd2e7b3b9a220a7205926e60488e673d9e4926d27772ce5"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.139"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0171ebb889e45aa68b44aee0859b3eede84c6f5f5c228e6f140c0b2a0a46cad6"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.139"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc1d3230c1de7932af58ad8ffbe1d784bd55efd5a9d84ac24f69c72d83543dfb"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.82"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.98"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"wasi 0.10.0+wasi-snapshot-preview1",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72c91f41dcb2f096c05f0873d667dceec1087ce5bcf984ec8ffb19acddbb3217"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"libc",
|
||||
"num_threads",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c"
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.10.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.83"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.83"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.83"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.83"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.83"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "xml-rs"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3"
|
|
@ -1,18 +0,0 @@
|
|||
[package]
|
||||
name = "gpconv"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
[features]
|
||||
osm = ["dep:osmio"]
|
||||
|
||||
# [lib]
|
||||
# crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
gpx="*"
|
||||
itertools="*"
|
||||
lazy_static="*"
|
||||
osmio={version="*", optional=true}
|
||||
wasm-bindgen="*"
|
|
@ -1,58 +0,0 @@
|
|||
This file documents the .gpc file format.
|
||||
|
||||
current version is version 2.
|
||||
|
||||
every number is encoded in little endian order.
|
||||
|
||||
# header
|
||||
|
||||
We start by a header of 5 16bytes unsigned ints.
|
||||
|
||||
- the first int is a marker with value 47490
|
||||
- second int is version of this file format
|
||||
- third int is **NP** the number of points composing the path
|
||||
- fourth int is **IP** the number of interest points bordering the path
|
||||
- fifth int is **LP** the number of interest points as encountered when looping through the path (higher than previous int since some points can be met several times)
|
||||
|
||||
# points
|
||||
|
||||
We continue with an array of **2 NP** f64 containing
|
||||
for each point its x and y coordinate.
|
||||
|
||||
# interest points
|
||||
|
||||
After that comes the storage for interest points.
|
||||
|
||||
- we start by an array of **2 IP** f64 containing
|
||||
the x and y coordinates of each interest point
|
||||
- we continue with an **IP** u8 array named **IPOINTS** containing the id of the point's type.
|
||||
you can see the `Interest` enum in `src/osm.rs` to know what int is what.
|
||||
for example 0 is a Bakery and 1 is a water point.
|
||||
|
||||
Now we need to store the relationship between segments and points.
|
||||
The idea is that in a display phase we don't want to loop on all interest points
|
||||
to figure out if they should appear on the map or not.
|
||||
We'll use the fact that we now the segments we want to display and therefore we should only
|
||||
need to display the points bordering these segments.
|
||||
|
||||
- we store an array **LOOP** of **LP** u16 indices of interest points in **IPOINTS**
|
||||
|
||||
while this is a contiguous array it contains points along the path grouped in buckets of 5 points.
|
||||
|
||||
to figure out on which segments they are :
|
||||
|
||||
- we store an array **STARTS** of **ceil(LP/5)** u16 indices of groups of segments.
|
||||
|
||||
Segments are grouped by 3.
|
||||
This array tells us on which group of segment is the first point of any bucket.
|
||||
|
||||
## display algorithm
|
||||
|
||||
If we want to display the interest points for the segments between 10 and 16 for example we proceed
|
||||
as follows:
|
||||
|
||||
* segments are grouped by 3 so instead of segment indices of 10..=16 we will look at group indices 10/3 ..= 16/3 so 3..=5
|
||||
* we do a binary search of the highest number below 3 in the **STARTS** array. we call *s* the obtained index
|
||||
* we do a binary search of the smallest number above 5 in the **STARTS** array. we call *e* the obtained index
|
||||
* we now loop on all buckets between *s* and *e* that is : on all indices *i* in `LOOP[(s*5)..=(e*5)]`
|
||||
* display `IPOINTS[i]`
|
|
@ -1,78 +0,0 @@
|
|||
use super::Point;
|
||||
use lazy_static::lazy_static;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum Interest {
|
||||
Bakery,
|
||||
DrinkingWater,
|
||||
Toilets,
|
||||
// BikeShop,
|
||||
// ChargingStation,
|
||||
// Bank,
|
||||
// Supermarket,
|
||||
// Table,
|
||||
// TourismOffice,
|
||||
Artwork,
|
||||
// Pharmacy,
|
||||
}
|
||||
|
||||
impl Into<u8> for Interest {
|
||||
fn into(self) -> u8 {
|
||||
match self {
|
||||
Interest::Bakery => 0,
|
||||
Interest::DrinkingWater => 1,
|
||||
Interest::Toilets => 2,
|
||||
// Interest::BikeShop => 8,
|
||||
// Interest::ChargingStation => 4,
|
||||
// Interest::Bank => 5,
|
||||
// Interest::Supermarket => 6,
|
||||
// Interest::Table => 7,
|
||||
Interest::Artwork => 3,
|
||||
// Interest::Pharmacy => 9,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct InterestPoint {
|
||||
pub point: Point,
|
||||
pub interest: Interest,
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref INTERESTS: HashMap<(&'static str, &'static str), Interest> = {
|
||||
[
|
||||
(("shop", "bakery"), Interest::Bakery),
|
||||
(("amenity", "drinking_water"), Interest::DrinkingWater),
|
||||
(("amenity", "toilets"), Interest::Toilets),
|
||||
// (("shop", "bicycle"), Interest::BikeShop),
|
||||
// (("amenity", "charging_station"), Interest::ChargingStation),
|
||||
// (("amenity", "bank"), Interest::Bank),
|
||||
// (("shop", "supermarket"), Interest::Supermarket),
|
||||
// (("leisure", "picnic_table"), Interest::Table),
|
||||
// (("tourism", "information"), Interest::TourismOffice),
|
||||
(("tourism", "artwork"), Interest::Artwork),
|
||||
// (("amenity", "pharmacy"), Interest::Pharmacy),
|
||||
]
|
||||
.into_iter()
|
||||
.collect()
|
||||
};
|
||||
}
|
||||
|
||||
impl InterestPoint {
|
||||
pub fn color(&self) -> &'static str {
|
||||
match self.interest {
|
||||
Interest::Bakery => "red",
|
||||
Interest::DrinkingWater => "blue",
|
||||
Interest::Toilets => "brown",
|
||||
// Interest::BikeShop => "purple",
|
||||
// Interest::ChargingStation => "green",
|
||||
// Interest::Bank => "black",
|
||||
// Interest::Supermarket => "red",
|
||||
// Interest::Table => "pink",
|
||||
Interest::Artwork => "orange",
|
||||
// Interest::Pharmacy => "chartreuse",
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,575 +0,0 @@
|
|||
use itertools::Itertools;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fs::File;
|
||||
use std::io::{BufReader, BufWriter, Read, Write};
|
||||
use std::path::Path;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
use gpx::read;
|
||||
use gpx::Gpx;
|
||||
|
||||
mod interests;
|
||||
use interests::InterestPoint;
|
||||
|
||||
mod svg;
|
||||
|
||||
#[cfg(feature = "osm")]
|
||||
mod osm;
|
||||
#[cfg(feature = "osm")]
|
||||
use osm::{parse_osm_data, InterestPoint};
|
||||
|
||||
const LOWER_SHARP_TURN: f64 = 80.0 * std::f64::consts::PI / 180.0;
|
||||
const UPPER_SHARP_TURN: f64 = std::f64::consts::PI * 2.0 - LOWER_SHARP_TURN;
|
||||
|
||||
const KEY: u16 = 47490;
|
||||
const FILE_VERSION: u16 = 3;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub struct Point {
|
||||
x: f64,
|
||||
y: f64,
|
||||
}
|
||||
|
||||
impl Eq for Point {}
|
||||
impl std::hash::Hash for Point {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
unsafe { std::mem::transmute::<f64, u64>(self.x) }.hash(state);
|
||||
unsafe { std::mem::transmute::<f64, u64>(self.y) }.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl Point {
|
||||
fn squared_distance_between(&self, other: &Point) -> f64 {
|
||||
let dx = other.x - self.x;
|
||||
let dy = other.y - self.y;
|
||||
dx * dx + dy * dy
|
||||
}
|
||||
fn distance_to_segment(&self, v: &Point, w: &Point) -> f64 {
|
||||
let l2 = v.squared_distance_between(w);
|
||||
if l2 == 0.0 {
|
||||
return self.squared_distance_between(v).sqrt();
|
||||
}
|
||||
// Consider the line extending the segment, parameterized as v + t (w - v).
|
||||
// We find projection of point p onto the line.
|
||||
// It falls where t = [(p-v) . (w-v)] / |w-v|^2
|
||||
// We clamp t from [0,1] to handle points outside the segment vw.
|
||||
let x0 = self.x - v.x;
|
||||
let y0 = self.y - v.y;
|
||||
let x1 = w.x - v.x;
|
||||
let y1 = w.y - v.y;
|
||||
let dot = x0 * x1 + y0 * y1;
|
||||
let t = (dot / l2).min(1.0).max(0.0);
|
||||
|
||||
let proj = Point {
|
||||
x: v.x + x1 * t,
|
||||
y: v.y + y1 * t,
|
||||
};
|
||||
|
||||
proj.squared_distance_between(self).sqrt()
|
||||
}
|
||||
}
|
||||
|
||||
fn points<R: Read>(reader: R) -> (HashSet<Point>, Vec<Point>) {
|
||||
// read takes any io::Read and gives a Result<Gpx, Error>.
|
||||
let mut gpx: Gpx = read(reader).unwrap();
|
||||
eprintln!("we have {} tracks", gpx.tracks.len());
|
||||
|
||||
let mut waypoints = HashSet::new();
|
||||
|
||||
let points = gpx
|
||||
.tracks
|
||||
.pop()
|
||||
.unwrap()
|
||||
.segments
|
||||
.into_iter()
|
||||
.flat_map(|segment| segment.points.into_iter())
|
||||
.map(|p| {
|
||||
let is_commented = p.comment.is_some();
|
||||
let (x, y) = p.point().x_y();
|
||||
let p = Point { x, y };
|
||||
if is_commented {
|
||||
waypoints.insert(p);
|
||||
}
|
||||
p
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
(waypoints, points)
|
||||
}
|
||||
|
||||
// // NOTE: this angles idea could maybe be use to get dp from n^3 to n^2
|
||||
// fn acceptable_angles(p1: &(f64, f64), p2: &(f64, f64), epsilon: f64) -> (f64, f64) {
|
||||
// // first, convert p2's coordinates for p1 as origin
|
||||
// let (x1, y1) = *p1;
|
||||
// let (x2, y2) = *p2;
|
||||
// let (x, y) = (x2 - x1, y2 - y1);
|
||||
// // rotate so that (p1, p2) ends on x axis
|
||||
// let theta = y.atan2(x);
|
||||
// let rx = x * theta.cos() - y * theta.sin();
|
||||
// let ry = x * theta.sin() + y * theta.cos();
|
||||
// assert!(ry.abs() <= std::f64::EPSILON);
|
||||
//
|
||||
// // now imagine a line at an angle alpha.
|
||||
// // we want the distance d from (rx, 0) to our line
|
||||
// // we have sin(alpha) = d / rx
|
||||
// // limiting d to epsilon, we solve
|
||||
// // sin(alpha) = e / rx
|
||||
// // and get
|
||||
// // alpha = arcsin(e/rx)
|
||||
// let alpha = (epsilon / rx).asin();
|
||||
//
|
||||
// // now we just need to rotate back
|
||||
// let a1 = theta + alpha.abs();
|
||||
// let a2 = theta - alpha.abs();
|
||||
// assert!(a1 >= a2);
|
||||
// (a1, a2)
|
||||
// }
|
||||
//
|
||||
// // this is like ramer douglas peucker algorithm
|
||||
// // except that we advance from the start without knowing the end.
|
||||
// // each point we meet constrains the chosen segment's angle
|
||||
// // a bit more.
|
||||
// //
|
||||
// fn simplify(mut points: &[(f64, f64)]) -> Vec<(f64, f64)> {
|
||||
// let mut remaining_points = Vec::new();
|
||||
// while !points.is_empty() {
|
||||
// let (sx, sy) = points.first().unwrap();
|
||||
// let i = match points
|
||||
// .iter()
|
||||
// .enumerate()
|
||||
// .map(|(i, (x, y))| todo!("compute angles"))
|
||||
// .try_fold(
|
||||
// (0.0f64, std::f64::consts::FRAC_2_PI),
|
||||
// |(amin, amax), (i, (amin2, amax2))| -> Result<(f64, f64), usize> {
|
||||
// let new_amax = amax.min(amax2);
|
||||
// let new_amin = amin.max(amin2);
|
||||
// if new_amin >= new_amax {
|
||||
// Err(i)
|
||||
// } else {
|
||||
// Ok((new_amin, new_amax))
|
||||
// }
|
||||
// },
|
||||
// ) {
|
||||
// Err(i) => i,
|
||||
// Ok(_) => points.len(),
|
||||
// };
|
||||
// remaining_points.push(points.first().cloned().unwrap());
|
||||
// points = &points[i..];
|
||||
// }
|
||||
// remaining_points
|
||||
// }
|
||||
|
||||
fn extract_prog_dyn_solution(
|
||||
points: &[Point],
|
||||
start: usize,
|
||||
end: usize,
|
||||
cache: &HashMap<(usize, usize), (Option<usize>, usize)>,
|
||||
) -> Vec<Point> {
|
||||
if let Some(choice) = cache.get(&(start, end)).unwrap().0 {
|
||||
let mut v1 = extract_prog_dyn_solution(points, start, choice + 1, cache);
|
||||
let mut v2 = extract_prog_dyn_solution(points, choice, end, cache);
|
||||
v1.pop();
|
||||
v1.append(&mut v2);
|
||||
v1
|
||||
} else {
|
||||
vec![points[start], points[end - 1]]
|
||||
}
|
||||
}
|
||||
|
||||
fn simplify_prog_dyn(
|
||||
points: &[Point],
|
||||
start: usize,
|
||||
end: usize,
|
||||
epsilon: f64,
|
||||
cache: &mut HashMap<(usize, usize), (Option<usize>, usize)>,
|
||||
) -> usize {
|
||||
if let Some(val) = cache.get(&(start, end)) {
|
||||
val.1
|
||||
} else {
|
||||
let res = if end - start <= 2 {
|
||||
assert_eq!(end - start, 2);
|
||||
(None, end - start)
|
||||
} else {
|
||||
let first_point = &points[start];
|
||||
let last_point = &points[end - 1];
|
||||
|
||||
if points[(start + 1)..end]
|
||||
.iter()
|
||||
.map(|p| p.distance_to_segment(first_point, last_point))
|
||||
.all(|d| d <= epsilon)
|
||||
{
|
||||
(None, 2)
|
||||
} else {
|
||||
// now we test all possible cutting points
|
||||
((start + 1)..(end - 1)) //TODO: take middle min
|
||||
.map(|i| {
|
||||
let v1 = simplify_prog_dyn(points, start, i + 1, epsilon, cache);
|
||||
let v2 = simplify_prog_dyn(points, i, end, epsilon, cache);
|
||||
(Some(i), v1 + v2 - 1)
|
||||
})
|
||||
.min_by_key(|(_, v)| *v)
|
||||
.unwrap()
|
||||
}
|
||||
};
|
||||
cache.insert((start, end), res);
|
||||
res.1
|
||||
}
|
||||
}
|
||||
|
||||
fn rdp(points: &[Point], epsilon: f64) -> Vec<Point> {
|
||||
if points.len() <= 2 {
|
||||
points.iter().copied().collect()
|
||||
} else {
|
||||
if points.first().unwrap() == points.last().unwrap() {
|
||||
let first = points.first().unwrap();
|
||||
let index_farthest = points
|
||||
.iter()
|
||||
.enumerate()
|
||||
.skip(1)
|
||||
.max_by(|(_, p1), (_, p2)| {
|
||||
first
|
||||
.squared_distance_between(p1)
|
||||
.partial_cmp(&first.squared_distance_between(p2))
|
||||
.unwrap()
|
||||
})
|
||||
.map(|(i, _)| i)
|
||||
.unwrap();
|
||||
|
||||
let start = &points[..(index_farthest + 1)];
|
||||
let end = &points[index_farthest..];
|
||||
let mut res = rdp(start, epsilon);
|
||||
res.pop();
|
||||
res.append(&mut rdp(end, epsilon));
|
||||
res
|
||||
} else {
|
||||
let (index_farthest, farthest_distance) = points
|
||||
.iter()
|
||||
.map(|p| p.distance_to_segment(points.first().unwrap(), points.last().unwrap()))
|
||||
.enumerate()
|
||||
.max_by(|(_, d1), (_, d2)| {
|
||||
if d1.is_nan() {
|
||||
std::cmp::Ordering::Greater
|
||||
} else {
|
||||
if d2.is_nan() {
|
||||
std::cmp::Ordering::Less
|
||||
} else {
|
||||
d1.partial_cmp(d2).unwrap()
|
||||
}
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
if farthest_distance <= epsilon {
|
||||
vec![
|
||||
points.first().copied().unwrap(),
|
||||
points.last().copied().unwrap(),
|
||||
]
|
||||
} else {
|
||||
let start = &points[..(index_farthest + 1)];
|
||||
let end = &points[index_farthest..];
|
||||
let mut res = rdp(start, epsilon);
|
||||
res.pop();
|
||||
res.append(&mut rdp(end, epsilon));
|
||||
res
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn simplify_path(points: &[Point], epsilon: f64) -> Vec<Point> {
|
||||
if points.len() <= 600 {
|
||||
optimal_simplification(points, epsilon)
|
||||
} else {
|
||||
hybrid_simplification(points, epsilon)
|
||||
}
|
||||
}
|
||||
|
||||
fn save_gpc<W: Write>(
|
||||
mut writer: W,
|
||||
points: &[Point],
|
||||
waypoints: &HashSet<Point>,
|
||||
buckets: &[Bucket],
|
||||
) -> std::io::Result<()> {
|
||||
eprintln!("saving {} points", points.len());
|
||||
|
||||
let mut unique_interest_points = Vec::new();
|
||||
let mut correspondance = HashMap::new();
|
||||
let interests_on_path = buckets
|
||||
.iter()
|
||||
.flat_map(|b| &b.points)
|
||||
.map(|p| match correspondance.entry(*p) {
|
||||
std::collections::hash_map::Entry::Occupied(o) => *o.get(),
|
||||
std::collections::hash_map::Entry::Vacant(v) => {
|
||||
let index = unique_interest_points.len();
|
||||
unique_interest_points.push(*p);
|
||||
v.insert(index);
|
||||
index
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
writer.write_all(&KEY.to_le_bytes())?;
|
||||
writer.write_all(&FILE_VERSION.to_le_bytes())?;
|
||||
writer.write_all(&(points.len() as u16).to_le_bytes())?;
|
||||
writer.write_all(&(unique_interest_points.len() as u16).to_le_bytes())?;
|
||||
writer.write_all(&(interests_on_path.len() as u16).to_le_bytes())?;
|
||||
points
|
||||
.iter()
|
||||
.flat_map(|p| [p.x, p.y])
|
||||
.try_for_each(|c| writer.write_all(&c.to_le_bytes()))?;
|
||||
|
||||
let mut waypoints_bits = std::iter::repeat(0u8)
|
||||
.take(points.len() / 8 + if points.len() % 8 != 0 { 1 } else { 0 })
|
||||
.collect::<Vec<u8>>();
|
||||
points.iter().enumerate().for_each(|(i, p)| {
|
||||
if waypoints.contains(p) {
|
||||
waypoints_bits[i / 8] |= 1 << (i % 8)
|
||||
}
|
||||
});
|
||||
waypoints_bits
|
||||
.iter()
|
||||
.try_for_each(|byte| writer.write_all(&byte.to_le_bytes()))?;
|
||||
|
||||
unique_interest_points
|
||||
.iter()
|
||||
.flat_map(|p| [p.point.x, p.point.y])
|
||||
.try_for_each(|c| writer.write_all(&c.to_le_bytes()))?;
|
||||
|
||||
let counts: HashMap<_, usize> =
|
||||
unique_interest_points
|
||||
.iter()
|
||||
.fold(HashMap::new(), |mut h, p| {
|
||||
*h.entry(p.interest).or_default() += 1;
|
||||
h
|
||||
});
|
||||
counts.into_iter().for_each(|(interest, count)| {
|
||||
eprintln!("{:?} appears {} times", interest, count);
|
||||
});
|
||||
|
||||
unique_interest_points
|
||||
.iter()
|
||||
.map(|p| p.interest.into())
|
||||
.try_for_each(|i: u8| writer.write_all(&i.to_le_bytes()))?;
|
||||
|
||||
interests_on_path
|
||||
.iter()
|
||||
.map(|i| *i as u16)
|
||||
.try_for_each(|i| writer.write_all(&i.to_le_bytes()))?;
|
||||
|
||||
buckets
|
||||
.iter()
|
||||
.map(|b| b.start as u16)
|
||||
.try_for_each(|i| writer.write_all(&i.to_le_bytes()))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn optimal_simplification(points: &[Point], epsilon: f64) -> Vec<Point> {
|
||||
let mut cache = HashMap::new();
|
||||
simplify_prog_dyn(&points, 0, points.len(), epsilon, &mut cache);
|
||||
extract_prog_dyn_solution(&points, 0, points.len(), &cache)
|
||||
}
|
||||
|
||||
fn hybrid_simplification(points: &[Point], epsilon: f64) -> Vec<Point> {
|
||||
if points.len() <= 300 {
|
||||
optimal_simplification(points, epsilon)
|
||||
} else {
|
||||
if points.first().unwrap() == points.last().unwrap() {
|
||||
let first = points.first().unwrap();
|
||||
let index_farthest = points
|
||||
.iter()
|
||||
.enumerate()
|
||||
.skip(1)
|
||||
.max_by(|(_, p1), (_, p2)| {
|
||||
first
|
||||
.squared_distance_between(p1)
|
||||
.partial_cmp(&first.squared_distance_between(p2))
|
||||
.unwrap()
|
||||
})
|
||||
.map(|(i, _)| i)
|
||||
.unwrap();
|
||||
|
||||
let start = &points[..(index_farthest + 1)];
|
||||
let end = &points[index_farthest..];
|
||||
let mut res = hybrid_simplification(start, epsilon);
|
||||
res.pop();
|
||||
res.append(&mut hybrid_simplification(end, epsilon));
|
||||
res
|
||||
} else {
|
||||
let (index_farthest, farthest_distance) = points
|
||||
.iter()
|
||||
.map(|p| p.distance_to_segment(points.first().unwrap(), points.last().unwrap()))
|
||||
.enumerate()
|
||||
.max_by(|(_, d1), (_, d2)| {
|
||||
if d1.is_nan() {
|
||||
std::cmp::Ordering::Greater
|
||||
} else {
|
||||
if d2.is_nan() {
|
||||
std::cmp::Ordering::Less
|
||||
} else {
|
||||
d1.partial_cmp(d2).unwrap()
|
||||
}
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
if farthest_distance <= epsilon {
|
||||
vec![
|
||||
points.first().copied().unwrap(),
|
||||
points.last().copied().unwrap(),
|
||||
]
|
||||
} else {
|
||||
let start = &points[..(index_farthest + 1)];
|
||||
let end = &points[index_farthest..];
|
||||
let mut res = hybrid_simplification(start, epsilon);
|
||||
res.pop();
|
||||
res.append(&mut hybrid_simplification(end, epsilon));
|
||||
res
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Bucket {
|
||||
points: Vec<InterestPoint>,
|
||||
start: usize,
|
||||
}
|
||||
|
||||
fn position_interests_along_path(
|
||||
interests: &mut [InterestPoint],
|
||||
path: &[Point],
|
||||
d: f64,
|
||||
buckets_size: usize, // final points are indexed in buckets
|
||||
groups_size: usize, // how many segments are compacted together
|
||||
) -> Vec<Bucket> {
|
||||
interests.sort_unstable_by(|p1, p2| p1.point.x.partial_cmp(&p2.point.x).unwrap());
|
||||
// first compute for each segment a vec containing its nearby points
|
||||
let mut positions = Vec::new();
|
||||
for segment in path.windows(2) {
|
||||
let mut local_interests = Vec::new();
|
||||
let x0 = segment[0].x;
|
||||
let x1 = segment[1].x;
|
||||
let (xmin, xmax) = if x0 <= x1 { (x0, x1) } else { (x1, x0) };
|
||||
let i = interests.partition_point(|p| p.point.x < xmin - d);
|
||||
let interests = &interests[i..];
|
||||
let i = interests.partition_point(|p| p.point.x <= xmax + d);
|
||||
let interests = &interests[..i];
|
||||
for interest in interests {
|
||||
if interest.point.distance_to_segment(&segment[0], &segment[1]) <= d {
|
||||
local_interests.push(*interest);
|
||||
}
|
||||
}
|
||||
positions.push(local_interests);
|
||||
}
|
||||
// fuse points on chunks of consecutive segments together
|
||||
let grouped_positions = positions
|
||||
.chunks(groups_size)
|
||||
.map(|c| c.iter().flatten().unique().copied().collect::<Vec<_>>())
|
||||
.collect::<Vec<_>>();
|
||||
// now, group the points in buckets
|
||||
let chunks = grouped_positions
|
||||
.iter()
|
||||
.enumerate()
|
||||
.flat_map(|(i, points)| points.iter().map(move |p| (i, p)))
|
||||
.chunks(buckets_size);
|
||||
let mut buckets = Vec::new();
|
||||
for bucket_points in &chunks {
|
||||
let mut bucket_points = bucket_points.peekable();
|
||||
let start = bucket_points.peek().unwrap().0;
|
||||
let points = bucket_points.map(|(_, p)| *p).collect();
|
||||
buckets.push(Bucket { points, start });
|
||||
}
|
||||
buckets
|
||||
}
|
||||
|
||||
fn detect_sharp_turns(path: &[Point], waypoints: &mut HashSet<Point>) {
|
||||
path.iter()
|
||||
.tuple_windows()
|
||||
.map(|(a, b, c)| {
|
||||
let xd1 = b.x - a.x;
|
||||
let yd1 = b.y - a.y;
|
||||
let angle1 = yd1.atan2(xd1);
|
||||
|
||||
let xd2 = c.x - b.x;
|
||||
let yd2 = c.y - b.y;
|
||||
let angle2 = yd2.atan2(xd2);
|
||||
let adiff = angle2 - angle1;
|
||||
let adiff = if adiff < 0.0 {
|
||||
adiff + std::f64::consts::PI * 2.0
|
||||
} else {
|
||||
adiff
|
||||
};
|
||||
(adiff, b)
|
||||
})
|
||||
.filter_map(|(adiff, b)| {
|
||||
if adiff > LOWER_SHARP_TURN && adiff < UPPER_SHARP_TURN {
|
||||
Some(b)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.for_each(|b| {
|
||||
waypoints.insert(*b);
|
||||
});
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn convert_gpx_strings(input_str: &str) -> Vec<u8> {
|
||||
let mut interests = Vec::new();
|
||||
let mut output: Vec<u8> = Vec::new();
|
||||
convert_gpx(input_str.as_bytes(), &mut output, &mut interests);
|
||||
output
|
||||
}
|
||||
|
||||
pub fn convert_gpx_files(input_file: &str, interests: &mut [InterestPoint]) {
|
||||
let file = File::open(input_file).unwrap();
|
||||
let reader = BufReader::new(file);
|
||||
let output_path = Path::new(&input_file).with_extension("gpc");
|
||||
let writer = BufWriter::new(File::create(output_path).unwrap());
|
||||
convert_gpx(reader, writer, interests);
|
||||
}
|
||||
|
||||
fn convert_gpx<R: Read, W: Write>(
|
||||
input_reader: R,
|
||||
output_writer: W,
|
||||
interests: &mut [InterestPoint],
|
||||
) {
|
||||
// load all points composing the trace and mark commented points
|
||||
// as special waypoints.
|
||||
let (mut waypoints, p) = points(input_reader);
|
||||
|
||||
// detect sharp turns before path simplification to keep them
|
||||
detect_sharp_turns(&p, &mut waypoints);
|
||||
waypoints.insert(p.first().copied().unwrap());
|
||||
waypoints.insert(p.last().copied().unwrap());
|
||||
println!("we have {} waypoints", waypoints.len());
|
||||
|
||||
println!("initially we had {} points", p.len());
|
||||
|
||||
// simplify path
|
||||
let mut rp = Vec::new();
|
||||
let mut segment = Vec::new();
|
||||
for point in &p {
|
||||
segment.push(*point);
|
||||
if waypoints.contains(point) {
|
||||
if segment.len() >= 2 {
|
||||
let mut s = simplify_path(&segment, 0.00015);
|
||||
rp.append(&mut s);
|
||||
segment = rp.pop().into_iter().collect();
|
||||
}
|
||||
}
|
||||
}
|
||||
rp.append(&mut segment);
|
||||
println!("we now have {} points", rp.len());
|
||||
|
||||
// add interest points from open street map if we have any
|
||||
let buckets = position_interests_along_path(interests, &rp, 0.001, 5, 3);
|
||||
|
||||
// save_svg(
|
||||
// "test.svg",
|
||||
// &p,
|
||||
// &rp,
|
||||
// buckets.iter().flat_map(|b| &b.points),
|
||||
// &waypoints,
|
||||
// )
|
||||
// .unwrap();
|
||||
|
||||
save_gpc(output_writer, &rp, &waypoints, &buckets).unwrap();
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
use gpconv::convert_gpx_files;
|
||||
|
||||
fn main() {
|
||||
let input_file = std::env::args().nth(1).unwrap_or("m.gpx".to_string());
|
||||
let mut interests;
|
||||
|
||||
#[cfg(feature = "osm")]
|
||||
{
|
||||
let osm_file = std::env::args().nth(2);
|
||||
let mut interests = if let Some(osm) = osm_file {
|
||||
interests = parse_osm_data(osm);
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
}
|
||||
#[cfg(not(feature = "osm"))]
|
||||
{
|
||||
interests = Vec::new()
|
||||
}
|
||||
|
||||
convert_gpx_files(&input_file, &mut interests);
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
use super::Interest;
|
||||
use super::Point;
|
||||
use itertools::Itertools;
|
||||
use lazy_static::lazy_static;
|
||||
use osmio::OSMObjBase;
|
||||
use osmio::{prelude::*, ObjId};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::path::Path;
|
||||
|
||||
pub fn parse_osm_data<P: AsRef<Path>>(path: P) -> Vec<InterestPoint> {
|
||||
let reader = osmio::read_pbf(path).ok();
|
||||
reader
|
||||
.map(|mut reader| {
|
||||
let mut interests = Vec::new();
|
||||
for obj in reader.objects() {
|
||||
match obj {
|
||||
osmio::obj_types::ArcOSMObj::Node(n) => {
|
||||
n.lat_lon_f64().map(|(lat, lon)| {
|
||||
for p in n.tags().filter_map(move |(k, v)| {
|
||||
Interest::new(k, v).map(|i| InterestPoint {
|
||||
point: Point { x: lon, y: lat },
|
||||
interest: i,
|
||||
})
|
||||
}) {
|
||||
interests.push(p);
|
||||
}
|
||||
});
|
||||
}
|
||||
osmio::obj_types::ArcOSMObj::Way(w) => {}
|
||||
osmio::obj_types::ArcOSMObj::Relation(_) => {}
|
||||
}
|
||||
}
|
||||
interests
|
||||
})
|
||||
.unwrap_or_default()
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
use itertools::Itertools;
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
io::{BufWriter, Write},
|
||||
path::Path,
|
||||
};
|
||||
|
||||
use crate::{interests::InterestPoint, Point};
|
||||
|
||||
fn save_path<W: Write>(writer: &mut W, p: &[Point], stroke: &str) -> std::io::Result<()> {
|
||||
write!(
|
||||
writer,
|
||||
"<polyline fill='none' stroke='{}' stroke-width='0.2%' points='",
|
||||
stroke
|
||||
)?;
|
||||
p.iter()
|
||||
.try_for_each(|p| write!(writer, "{},{} ", p.x, p.y))?;
|
||||
writeln!(writer, "'/>")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// save svg file from given path and interest points.
|
||||
// useful for debugging path simplification and previewing traces.
|
||||
pub fn save_svg<'a, P: AsRef<Path>, I: IntoIterator<Item = &'a InterestPoint>>(
|
||||
filename: P,
|
||||
p: &[Point],
|
||||
rp: &[Point],
|
||||
interest_points: I,
|
||||
waypoints: &HashSet<Point>,
|
||||
) -> std::io::Result<()> {
|
||||
let mut writer = BufWriter::new(std::fs::File::create(filename)?);
|
||||
let (xmin, xmax) = p
|
||||
.iter()
|
||||
.map(|p| p.x)
|
||||
.minmax_by(|a, b| a.partial_cmp(b).unwrap())
|
||||
.into_option()
|
||||
.unwrap();
|
||||
|
||||
let (ymin, ymax) = p
|
||||
.iter()
|
||||
.map(|p| p.y)
|
||||
.minmax_by(|a, b| a.partial_cmp(b).unwrap())
|
||||
.into_option()
|
||||
.unwrap();
|
||||
|
||||
writeln!(
|
||||
&mut writer,
|
||||
"<svg width='800' height='600' viewBox='{} {} {} {}'>",
|
||||
xmin,
|
||||
ymin,
|
||||
xmax - xmin,
|
||||
ymax - ymin
|
||||
)?;
|
||||
write!(
|
||||
&mut writer,
|
||||
"<rect fill='white' x='{}' y='{}' width='{}' height='{}'/>",
|
||||
xmin,
|
||||
ymin,
|
||||
xmax - xmin,
|
||||
ymax - ymin
|
||||
)?;
|
||||
|
||||
save_path(&mut writer, &p, "red")?;
|
||||
save_path(&mut writer, &rp, "black")?;
|
||||
|
||||
for point in interest_points {
|
||||
writeln!(
|
||||
&mut writer,
|
||||
"<circle cx='{}' cy='{}' fill='{}' r='0.8%'/>",
|
||||
point.point.x,
|
||||
point.point.y,
|
||||
point.color(),
|
||||
)?;
|
||||
}
|
||||
|
||||
waypoints.iter().try_for_each(|p| {
|
||||
writeln!(
|
||||
&mut writer,
|
||||
"<circle cx='{}' cy='{}' fill='black' r='0.3%'/>",
|
||||
p.x, p.y,
|
||||
)
|
||||
})?;
|
||||
|
||||
writeln!(&mut writer, "</svg>")?;
|
||||
Ok(())
|
||||
}
|
Loading…
Reference in New Issue