Vendor dependencies for 0.3.0 release

This commit is contained in:
2025-09-27 10:29:08 -05:00
parent 0c8d39d483
commit 82ab7f317b
26803 changed files with 16134934 additions and 0 deletions

1
vendor/kd-tree/.cargo-checksum.json vendored Normal file
View File

@@ -0,0 +1 @@
{"files":{"Cargo.lock":"a0f555cc1cbb1d22b0ff70b63731b2d13898d74269ec5c2922eaab68191ff93f","Cargo.toml":"be28dff36b921b8f5c79e1ac89d0302856b29d19e5979bbc7bdad238b669a5f3","LICENSE":"b2eb00924c656cf10ade09f47cf10336c3195ffd7218e6615c611c0d72bc6ef2","README.md":"1e1ba996d412c076fae6b4021100b17bb30b58bfaa720760b98875b507f2c451","benches/benchmark.rs":"97ebda8946ba33a20996c82c6306bba8de40f9318b86abcfc2381c19f29721d1","src/lib.rs":"14a0ea09cf8535e85d145cfb07c639f3e81f10c5451beef386139ca39e1af848","src/nalgebra.rs":"f1d2b8fdcf5f910eeb73dca7e8ac1d74cfa0b66d7aef8c04467e08d503760c0b","src/nearest.rs":"7aea2e6c0c0efd65f34df6992d19b58a80241e9ae005d3b8684c20ac78abffe6","src/nearests.rs":"76a2a3cf6b30f8abb4c97273d270b45d2fb4dfbd0dd37bbaa1a3046ca122b833","src/sort.rs":"b83f3de6876ef91578b539410a975e9daa6db04dedcceb550bf7ea7ee12ef9c2","src/tests.rs":"343fca1b39d32fc28050d0ed736d939d0bc2bfc402fcb3f6e20e4eb73b6a8b77","src/within.rs":"58be1690ed334a829baffe4e7dd878b36bf552a42e21bac6a867336745e72961"},"package":"10cba89e4275e55bed515724fd6d7888861c1afb9e3a1ef2c4b001b1894b41c7"}

905
vendor/kd-tree/Cargo.lock generated vendored Normal file
View File

@@ -0,0 +1,905 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "aho-corasick"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
[[package]]
name = "anes"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
[[package]]
name = "anstyle"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
[[package]]
name = "approx"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6"
dependencies = [
"num-traits",
]
[[package]]
name = "autocfg"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "bitflags"
version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
[[package]]
name = "bumpalo"
version = "3.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
[[package]]
name = "bytemuck"
version = "1.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6b1fc10dbac614ebc03540c9dbd60e83887fda27794998c6528f1782047d540"
[[package]]
name = "cast"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "ciborium"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e"
dependencies = [
"ciborium-io",
"ciborium-ll",
"serde",
]
[[package]]
name = "ciborium-io"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757"
[[package]]
name = "ciborium-ll"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9"
dependencies = [
"ciborium-io",
"half",
]
[[package]]
name = "clap"
version = "4.5.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071"
dependencies = [
"clap_builder",
]
[[package]]
name = "clap_builder"
version = "4.5.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2"
dependencies = [
"anstyle",
"clap_lex",
]
[[package]]
name = "clap_lex"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
[[package]]
name = "criterion"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f"
dependencies = [
"anes",
"cast",
"ciborium",
"clap",
"criterion-plot",
"is-terminal",
"itertools",
"num-traits",
"once_cell",
"oorandom",
"plotters",
"rayon",
"regex",
"serde",
"serde_derive",
"serde_json",
"tinytemplate",
"walkdir",
]
[[package]]
name = "criterion-plot"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1"
dependencies = [
"cast",
"itertools",
]
[[package]]
name = "crossbeam-deque"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
dependencies = [
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
[[package]]
name = "crunchy"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929"
[[package]]
name = "either"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
[[package]]
name = "fux_kdtree"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "216bf8256834a87394bf0364f82a92444ee8a00c757630a02a2bf278456f74e7"
[[package]]
name = "getrandom"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0"
dependencies = [
"cfg-if",
"libc",
"r-efi",
"wasi",
]
[[package]]
name = "half"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9"
dependencies = [
"cfg-if",
"crunchy",
]
[[package]]
name = "hermit-abi"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbd780fe5cc30f81464441920d82ac8740e2e46b29a6fad543ddd075229ce37e"
[[package]]
name = "is-terminal"
version = "0.4.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9"
dependencies = [
"hermit-abi",
"libc",
"windows-sys",
]
[[package]]
name = "itertools"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
[[package]]
name = "js-sys"
version = "0.3.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
dependencies = [
"once_cell",
"wasm-bindgen",
]
[[package]]
name = "kd-tree"
version = "0.6.1"
dependencies = [
"criterion",
"fux_kdtree",
"kdtree",
"nalgebra",
"num-traits",
"ordered-float",
"paste",
"rand",
"rayon",
"serde",
"serde_json",
"typenum",
]
[[package]]
name = "kdtree"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f0a0e9f770b65bac9aad00f97a67ab5c5319effed07f6da385da3c2115e47ba"
dependencies = [
"num-traits",
"thiserror",
]
[[package]]
name = "libc"
version = "0.2.172"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
[[package]]
name = "log"
version = "0.4.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
[[package]]
name = "matrixmultiply"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9380b911e3e96d10c1f415da0876389aaf1b56759054eeb0de7df940c456ba1a"
dependencies = [
"autocfg",
"rawpointer",
]
[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "nalgebra"
version = "0.33.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26aecdf64b707efd1310e3544d709c5c0ac61c13756046aaaba41be5c4f66a3b"
dependencies = [
"approx",
"matrixmultiply",
"nalgebra-macros",
"num-complex",
"num-rational",
"num-traits",
"serde",
"simba",
"typenum",
]
[[package]]
name = "nalgebra-macros"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "254a5372af8fc138e36684761d3c0cdb758a4410e938babcff1c860ce14ddbfc"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "num-bigint"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
dependencies = [
"num-integer",
"num-traits",
]
[[package]]
name = "num-complex"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
dependencies = [
"num-traits",
"serde",
]
[[package]]
name = "num-integer"
version = "0.1.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
dependencies = [
"num-traits",
]
[[package]]
name = "num-rational"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
dependencies = [
"num-bigint",
"num-integer",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
]
[[package]]
name = "once_cell"
version = "1.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
[[package]]
name = "oorandom"
version = "11.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e"
[[package]]
name = "ordered-float"
version = "5.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2c1f9f56e534ac6a9b8a4600bdf0f530fb393b5f393e7b4d03489c3cf0c3f01"
dependencies = [
"num-traits",
]
[[package]]
name = "paste"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
[[package]]
name = "plotters"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747"
dependencies = [
"num-traits",
"plotters-backend",
"plotters-svg",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "plotters-backend"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a"
[[package]]
name = "plotters-svg"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670"
dependencies = [
"plotters-backend",
]
[[package]]
name = "ppv-lite86"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
dependencies = [
"zerocopy",
]
[[package]]
name = "proc-macro2"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [
"proc-macro2",
]
[[package]]
name = "r-efi"
version = "5.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
[[package]]
name = "rand"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
dependencies = [
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
dependencies = [
"getrandom",
]
[[package]]
name = "rawpointer"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
[[package]]
name = "rayon"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
dependencies = [
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
version = "1.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
dependencies = [
"crossbeam-deque",
"crossbeam-utils",
]
[[package]]
name = "regex"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "rustversion"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
[[package]]
name = "ryu"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
[[package]]
name = "safe_arch"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96b02de82ddbe1b636e6170c21be622223aea188ef2e139be0a5b219ec215323"
dependencies = [
"bytemuck",
]
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]]
name = "serde"
version = "1.0.219"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.219"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.140"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
dependencies = [
"itoa",
"memchr",
"ryu",
"serde",
]
[[package]]
name = "simba"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3a386a501cd104797982c15ae17aafe8b9261315b5d07e3ec803f2ea26be0fa"
dependencies = [
"approx",
"num-complex",
"num-traits",
"paste",
"wide",
]
[[package]]
name = "syn"
version = "2.0.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "thiserror"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tinytemplate"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
dependencies = [
"serde",
"serde_json",
]
[[package]]
name = "typenum"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
[[package]]
name = "unicode-ident"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "walkdir"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
dependencies = [
"same-file",
"winapi-util",
]
[[package]]
name = "wasi"
version = "0.14.2+wasi-0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
dependencies = [
"wit-bindgen-rt",
]
[[package]]
name = "wasm-bindgen"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
dependencies = [
"cfg-if",
"once_cell",
"rustversion",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
dependencies = [
"bumpalo",
"log",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
dependencies = [
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
dependencies = [
"unicode-ident",
]
[[package]]
name = "web-sys"
version = "0.3.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "wide"
version = "0.7.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41b5576b9a81633f3e8df296ce0063042a73507636cbe956c61133dd7034ab22"
dependencies = [
"bytemuck",
"safe_arch",
]
[[package]]
name = "winapi-util"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [
"windows-sys",
]
[[package]]
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "wit-bindgen-rt"
version = "0.39.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
dependencies = [
"bitflags",
]
[[package]]
name = "zerocopy"
version = "0.8.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be"
dependencies = [
"proc-macro2",
"quote",
"syn",
]

90
vendor/kd-tree/Cargo.toml vendored Normal file
View File

@@ -0,0 +1,90 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies.
#
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.
[package]
edition = "2018"
name = "kd-tree"
version = "0.6.1"
authors = ["Yuichiro Terada <terada.yuichiro@gmail.com>"]
build = false
autolib = false
autobins = false
autoexamples = false
autotests = false
autobenches = false
description = "k-dimensional tree"
documentation = "https://docs.rs/kd-tree"
readme = "README.md"
keywords = [
"kdtree",
"nearest-neighbor",
"closest-point",
"pointcloud",
]
license = "MIT"
repository = "https://github.com/u1roh/kd-tree"
[features]
nalgebra-serde = [
"serde",
"nalgebra",
"nalgebra/serde-serialize",
]
[lib]
name = "kd_tree"
path = "src/lib.rs"
[[bench]]
name = "benchmark"
path = "benches/benchmark.rs"
harness = false
[dependencies.nalgebra]
version = "0.33.2"
optional = true
[dependencies.num-traits]
version = "0.2.17"
[dependencies.ordered-float]
version = "5.0.0"
[dependencies.paste]
version = "1.0.14"
[dependencies.rayon]
version = "1.10.0"
optional = true
[dependencies.serde]
version = "1.0.195"
features = ["derive"]
optional = true
[dependencies.typenum]
version = "1.17.0"
[dev-dependencies.criterion]
version = "0.5.1"
[dev-dependencies.fux_kdtree]
version = "0.2.0"
package = "fux_kdtree"
[dev-dependencies.kdtree]
version = "0.7.0"
[dev-dependencies.rand]
version = "0.9.1"
[dev-dependencies.serde_json]
version = "1.0"

19
vendor/kd-tree/LICENSE vendored Normal file
View File

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

215
vendor/kd-tree/README.md vendored Normal file
View File

@@ -0,0 +1,215 @@
# kd-tree
k-dimensional tree in Rust.
Fast, simple, and easy to use.
## Usage
```rust
// construct kd-tree
let kdtree = kd_tree::KdTree::build_by_ordered_float(vec![
[1.0, 2.0, 3.0],
[3.0, 1.0, 2.0],
[2.0, 3.0, 1.0],
]);
// search the nearest neighbor
let found = kdtree.nearest(&[3.1, 0.9, 2.1]).unwrap();
assert_eq!(found.item, &[3.0, 1.0, 2.0]);
// search k-nearest neighbors
let found = kdtree.nearests(&[1.5, 2.5, 1.8], 2);
assert_eq!(found[0].item, &[2.0, 3.0, 1.0]);
assert_eq!(found[1].item, &[1.0, 2.0, 3.0]);
// search points within a sphere
let found = kdtree.within_radius(&[2.0, 1.5, 2.5], 1.5);
assert_eq!(found.len(), 2);
assert!(found.iter().any(|&&p| p == [1.0, 2.0, 3.0]));
assert!(found.iter().any(|&&p| p == [3.0, 1.0, 2.0]));
```
## With or without `KdPoint`
`KdPoint` trait represents k-dimensional point.
You can live with or without `KdPoint`.
### With `KdPoint` explicitly
```rust
use kd_tree::{KdPoint, KdTree};
// define your own item type.
struct Item {
point: [f64; 2],
id: usize,
}
// implement `KdPoint` for your item type.
impl KdPoint for Item {
type Scalar = f64;
type Dim = typenum::U2; // 2 dimensional tree.
fn at(&self, k: usize) -> f64 { self.point[k] }
}
// construct kd-tree from `Vec<Item>`.
// Note: you need to use `build_by_ordered_float()` because f64 doesn't implement `Ord` trait.
let kdtree: KdTree<Item> = KdTree::build_by_ordered_float(vec![
Item { point: [1.0, 2.0], id: 111 },
Item { point: [2.0, 3.0], id: 222 },
Item { point: [3.0, 4.0], id: 333 },
]);
// search nearest item from [1.9, 3.1]
assert_eq!(kdtree.nearest(&[1.9, 3.1]).unwrap().item.id, 222);
```
### With `KdPoint` implicitly
`KdPoint` trait is implemented for fixed-sized array of numerical types, such as `[f64; 3]` or `[i32, 2]` etc.
So you can build kd-trees of those types without custom implementation of `KdPoint`.
```rust
let items: Vec<[i32; 3]> = vec![[1, 2, 3], [3, 1, 2], [2, 3, 1]];
let kdtree = kd_tree::KdTree::build(items);
assert_eq!(kdtree.nearest(&[3, 1, 2]).unwrap().item, &[3, 1, 2]);
```
`KdPoint` trait is also implemented for tuple of a `KdPoint` and an arbitrary type, like `(P, T)` where `P: KdPoint`.
And a type alias named `KdMap<P, T>` is defined as `KdTree<(P, T)>`.
So you can build a kd-tree from key-value pairs, as below:
```rust
let kdmap: kd_tree::KdMap<[isize; 3], &'static str> = kd_tree::KdMap::build(vec![
([1, 2, 3], "foo"),
([2, 3, 1], "bar"),
([3, 1, 2], "buzz"),
]);
assert_eq!(kdmap.nearest(&[3, 1, 2]).unwrap().item.1, "buzz");
```
#### `nalgebra` feature
`KdPoint` trait is implemented for `nalgebra`'s vectors and points.
Enable `nalgebra` feature in your Cargo.toml:
```toml
kd-tree = { version = "...", features = ["nalgebra"] }
```
Then, you can use it as follows:
```rust
use nalgebra::Point3;
let items: Vec<Point3<i32>> = vec![
Point3::new(1, 2, 3),
Point3::new(3, 1, 2),
Point3::new(2, 3, 1)
];
let kdtree = kd_tree::KdTree::build(items);
let query = Point3::new(3, 1, 2);
assert_eq!(kdtree.nearest(&query).unwrap().item, &query);
```
### Without `KdPoint`
```rust
use std::collections::HashMap;
let items: HashMap<&'static str, [i32; 2]> = vec![
("a", [10, 20]),
("b", [20, 10]),
("c", [20, 20]),
].into_iter().collect();
let kdtree = kd_tree::KdTree2::build_by_key(items.keys().collect(), |key, k| items[*key][k]);
assert_eq!(kdtree.nearest_by(&[18, 21], |key, k| items[*key][k]).unwrap().item, &&"c");
```
## To own, or not to own
`KdSliceN<T, N>` and `KdTreeN<T, N>` are similar to `str` and `String`, or `Path` and `PathBuf`.
- `KdSliceN<T, N>` doesn't own its buffer, but `KdTreeN<T, N>`.
- `KdSliceN<T, N>` is not `Sized`, so it must be dealed in reference mannar.
- `KdSliceN<T, N>` implements `Deref` to `[T]`.
- `KdTreeN<T, N>` implements `Deref` to `KdSliceN<T, N>`.
- Unlike `PathBuf` or `String`, which are mutable, `KdTreeN<T, N>` is immutable.
`&KdSliceN<T, N>` can be constructed directly, not via `KdTreeN`, as below:
```rust
let mut items: Vec<[i32; 3]> = vec![[1, 2, 3], [3, 1, 2], [2, 3, 1]];
let kdtree = kd_tree::KdSlice::sort(&mut items);
assert_eq!(kdtree.nearest(&[3, 1, 2]).unwrap().item, &[3, 1, 2]);
```
## `KdIndexTreeN`
A `KdIndexTreeN` refers a slice of items, `[T]`, and contains kd-tree of indices to the items, `KdTreeN<usize, N>`.
Unlike [`KdSlice::sort`], [`KdIndexTree::build`] doesn't sort input items.
```rust
let items = vec![[1, 2, 3], [3, 1, 2], [2, 3, 1]];
let kdtree = kd_tree::KdIndexTree::build(&items);
assert_eq!(kdtree.nearest(&[3, 1, 2]).unwrap().item, &1); // nearest() returns an index of found item.
```
## Features
### "serde" feature
```toml
[dependencies]
kd-tree = { version = "...", features = ["serde"] }
```
You can serialize/deserialize `KdTree<{serializable type}>` with this feature.
```rust
let src: KdTree3<[i32; 3]> = KdTree::build(vec![[1, 2, 3], [4, 5, 6]]);
let json = serde_json::to_string(&src).unwrap();
assert_eq!(json, "[[1,2,3],[4,5,6]]");
let dst: KdTree3<[i32; 3]> = serde_json::from_str(&json).unwrap();
assert_eq!(src, dst);
```
### "nalgebra" feature
```toml
[dependencies]
kd-tree = { version = "...", features = ["nalgebra"] }
```
see [above](#nalgebra-feature)
### "nalgebra-serde" feature
```toml
[dependencies]
kd-tree = { version = "...", features = ["nalgebra-serde"] }
```
You can serialize/deserialize `KdTree<{nalgebra type}>` with this feature.
```rust
use ::nalgebra as na;
let src: KdTree<na::Point3<f64>> = KdTree::build_by_ordered_float(vec![
na::Point3::new(1.0, 2.0, 3.0),
na::Point3::new(4.0, 5.0, 6.0),
]);
let json = serde_json::to_string(&src).unwrap();
assert_eq!(json, "[[1.0,2.0,3.0],[4.0,5.0,6.0]]");
let dst: KdTree3<na::Point3<f64>> = serde_json::from_str(&json).unwrap();
assert_eq!(src, dst);
```
### "rayon" feature
```toml
[dependencies]
kd-tree = { version = "...", features = ["rayon"] }
```
You can build a kd-tree faster with `rayon`.
```rust
let kdtree = KdTree::par_build_by_ordered_float(vec![...]);
```
## License
This library is distributed under the [MIT License](https://opensource.org/licenses/MIT).

302
vendor/kd-tree/benches/benchmark.rs vendored Normal file
View File

@@ -0,0 +1,302 @@
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use kd_tree::*;
fn bench_kdtree_construction(c: &mut Criterion) {
let mut group = c.benchmark_group("construct");
for log10n in &[2, 3, 4] {
group.bench_with_input(
BenchmarkId::new("kd_tree (f64)", log10n),
log10n,
|b, log10n| {
let points = gen_points3d(10usize.pow(*log10n));
b.iter(|| KdTree::build_by_ordered_float(points.clone()));
},
);
group.bench_with_input(
BenchmarkId::new("kd_tree (i32)", log10n),
log10n,
|b, log10n| {
let points = gen_points3i(10usize.pow(*log10n));
b.iter(|| KdTree::build(points.clone()));
},
);
#[cfg(feature = "rayon")]
{
group.bench_with_input(
BenchmarkId::new("kd_tree + rayon (f64)", log10n),
log10n,
|b, log10n| {
let points = gen_points3d(10usize.pow(*log10n));
b.iter(|| KdTree::par_build_by_ordered_float(points.clone()));
},
);
group.bench_with_input(
BenchmarkId::new("kd_tree + rayon (i32)", log10n),
log10n,
|b, log10n| {
let points = gen_points3i(10usize.pow(*log10n));
b.iter(|| KdTree::par_build(points.clone()));
},
);
}
group.bench_with_input(
BenchmarkId::new("kd_index_tree", log10n),
log10n,
|b, log10n| {
let points = gen_points3d(10usize.pow(*log10n));
b.iter(|| KdIndexTree::build_by_ordered_float(&points));
},
);
group.bench_with_input(
BenchmarkId::new("fux_kdtree", log10n),
log10n,
|b, log10n| {
let points = gen_points3d(10usize.pow(*log10n));
b.iter(|| fux_kdtree::kdtree::Kdtree::new(&mut points.clone()));
},
);
group.bench_with_input(BenchmarkId::new("kdtree", log10n), log10n, |b, log10n| {
let points = gen_points3d(10usize.pow(*log10n));
b.iter(|| {
let mut kdtree = kdtree::KdTree::new(3);
for p in &points {
kdtree.add(&p.coord, p.id).unwrap();
}
})
});
}
}
fn bench_kdtree_nearest_search(c: &mut Criterion) {
use rand::Rng;
let mut rng = rand::thread_rng();
let mut group = c.benchmark_group("nearest");
for log10n in &[2, 3, 4] {
group.bench_with_input(
BenchmarkId::new("kd_tree (f64)", log10n),
log10n,
|b, log10n| {
let kdtree = KdTree::build_by_ordered_float(gen_points3d(10usize.pow(*log10n)));
b.iter(|| {
let i = rng.gen::<usize>() % kdtree.len();
assert_eq!(
kdtree.nearest(&kdtree[i]).unwrap().item.coord,
kdtree[i].coord
);
});
},
);
group.bench_with_input(
BenchmarkId::new("kd_tree (i32)", log10n),
log10n,
|b, log10n| {
let kdtree = KdTree::build(gen_points3i(10usize.pow(*log10n)));
b.iter(|| {
let i = rng.gen::<usize>() % kdtree.len();
assert_eq!(
kdtree.nearest(&kdtree[i]).unwrap().item.coord,
kdtree[i].coord
);
});
},
);
group.bench_with_input(
BenchmarkId::new("kd_index_tree", log10n),
log10n,
|b, log10n| {
let points = gen_points3d(10usize.pow(*log10n));
let kdtree = KdIndexTree::build_by_ordered_float(&points);
b.iter(|| {
let i = rng.gen::<usize>() % points.len();
assert_eq!(kdtree.nearest(&points[i]).unwrap().item, &i);
});
},
);
group.bench_with_input(
BenchmarkId::new("kd_tree/nearests", log10n),
log10n,
|b, log10n| {
let kdtree = KdTree::build_by_ordered_float(gen_points3d(10usize.pow(*log10n)));
b.iter(|| {
let i = rng.gen::<usize>() % kdtree.len();
assert_eq!(
kdtree.nearests(&kdtree[i], 1)[0].item.coord,
kdtree[i].coord
);
});
},
);
group.bench_with_input(
BenchmarkId::new("fux_kdtree", log10n),
log10n,
|b, log10n| {
let mut points = gen_points3d(10usize.pow(*log10n));
let kdtree = fux_kdtree::kdtree::Kdtree::new(&mut points);
b.iter(|| {
let i = rng.gen::<usize>() % points.len();
assert_eq!(kdtree.nearest_search(&points[i]).coord, points[i].coord);
});
},
);
group.bench_with_input(BenchmarkId::new("kdtree", log10n), log10n, |b, log10n| {
let points = gen_points3d(10usize.pow(*log10n));
let mut kdtree = kdtree::KdTree::new(3);
for p in &points {
kdtree.add(&p.coord, p.id).unwrap();
}
b.iter(|| {
let i = rng.gen::<usize>() % points.len();
assert_eq!(
kdtree
.nearest(&points[i].coord, 1, &kdtree::distance::squared_euclidean)
.unwrap()[0]
.1,
&points[i].id
);
})
});
}
}
fn bench_kdtree_k_nearest_search(c: &mut Criterion) {
use rand::Rng;
let mut rng = rand::thread_rng();
let mut group = c.benchmark_group("nearests");
const N: usize = 100000;
let points = gen_points3d(N);
let kdtree = {
let mut kdtree = kdtree::KdTree::new(3);
for p in &points {
kdtree.add(&p.coord, p.id).unwrap();
}
kdtree
};
let kd_tree = KdTree::build_by_ordered_float(points.clone());
let kd_index_tree = KdIndexTree::build_by_ordered_float(&points);
for k in &[1, 5, 10, 20, 50] {
group.bench_with_input(BenchmarkId::new("kd_tree", k), k, |b, k| {
b.iter(|| {
let i = rng.gen::<usize>() % kd_tree.len();
let nearests = kd_tree.nearests(&kd_tree[i], *k);
assert_eq!(nearests[0].item.coord, kd_tree[i].coord);
});
});
group.bench_with_input(BenchmarkId::new("kd_index_tree", k), k, |b, k| {
b.iter(|| {
let i = rng.gen::<usize>() % points.len();
let nearests = kd_index_tree.nearests(&points[i], *k);
assert_eq!(nearests[0].item, &i);
});
});
group.bench_with_input(BenchmarkId::new("kdtree", k), k, |b, k| {
b.iter(|| {
let i = rng.gen::<usize>() % N;
assert_eq!(
kdtree
.nearest(&points[i].coord, *k, &kdtree::distance::squared_euclidean)
.unwrap()[0]
.1,
&points[i].id
);
})
});
}
}
fn bench_kdtree_within_radius(c: &mut Criterion) {
use rand::Rng;
let mut rng = rand::thread_rng();
let mut group = c.benchmark_group("within_radius");
const N: usize = 100000;
let points = gen_points3d(N);
let kdtree = {
let mut kdtree = kdtree::KdTree::new(3);
for p in &points {
kdtree.add(&p.coord, p.id).unwrap();
}
kdtree
};
let kd_tree = KdTree::build_by_ordered_float(points.clone());
let kd_index_tree = KdIndexTree::build_by_ordered_float(&points);
for radius in &[0.05, 0.1, 0.2, 0.4] {
group.bench_with_input(BenchmarkId::new("kd_tree", radius), radius, |b, radius| {
b.iter(|| {
let i = rng.gen::<usize>() % kd_tree.len();
let _neighbors = kd_tree.within_radius(&kd_tree[i], *radius);
});
});
group.bench_with_input(
BenchmarkId::new("kd_index_tree", radius),
radius,
|b, radius| {
b.iter(|| {
let i = rng.gen::<usize>() % kd_tree.len();
let _neighbors = kd_index_tree.within_radius(&points[i], *radius);
});
},
);
group.bench_with_input(BenchmarkId::new("kdtree", radius), radius, |b, radius| {
b.iter(|| {
let i = rng.gen::<usize>() % N;
let _neighbors = kdtree
.within(
&points[i].coord,
*radius * *radius,
&kdtree::distance::squared_euclidean,
)
.unwrap();
})
});
}
}
criterion_group!(benches1, bench_kdtree_construction);
criterion_group!(benches2, bench_kdtree_nearest_search);
criterion_group!(benches3, bench_kdtree_k_nearest_search);
criterion_group!(benches4, bench_kdtree_within_radius);
criterion_main!(benches1, benches2, benches3, benches4);
#[derive(Debug, Clone, Copy, PartialEq)]
struct TestItem<T> {
coord: [T; 3],
id: usize,
}
impl<T: num_traits::NumAssign + Copy + PartialOrd> KdPoint for TestItem<T> {
type Scalar = T;
type Dim = typenum::U3;
fn at(&self, k: usize) -> T {
self.coord[k]
}
}
impl fux_kdtree::kdtree::KdtreePointTrait for TestItem<f64> {
fn dims(&self) -> &[f64] {
&self.coord
}
}
fn gen_points3d(count: usize) -> Vec<TestItem<f64>> {
use rand::Rng;
let mut rng = rand::thread_rng();
let mut points = Vec::with_capacity(count);
for id in 0..count {
let coord = [rng.gen(), rng.gen(), rng.gen()];
points.push(TestItem { coord, id });
}
points
}
fn gen_points3i(count: usize) -> Vec<TestItem<i32>> {
use rand::Rng;
let mut rng = rand::thread_rng();
let mut points = Vec::with_capacity(count);
const N: i32 = 1000;
for id in 0..count {
let coord = [
rng.gen::<i32>() % N,
rng.gen::<i32>() % N,
rng.gen::<i32>() % N,
];
points.push(TestItem { coord, id });
}
points
}

840
vendor/kd-tree/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,840 @@
//! k-dimensional tree.
//!
//! # Usage
//! ```
//! // construct kd-tree
//! let kdtree = kd_tree::KdTree::build_by_ordered_float(vec![
//! [1.0, 2.0, 3.0],
//! [3.0, 1.0, 2.0],
//! [2.0, 3.0, 1.0],
//! ]);
//!
//! // search the nearest neighbor
//! let found = kdtree.nearest(&[3.1, 0.9, 2.1]).unwrap();
//! assert_eq!(found.item, &[3.0, 1.0, 2.0]);
//!
//! // search k-nearest neighbors
//! let found = kdtree.nearests(&[1.5, 2.5, 1.8], 2);
//! assert_eq!(found[0].item, &[2.0, 3.0, 1.0]);
//! assert_eq!(found[1].item, &[1.0, 2.0, 3.0]);
//!
//! // search points within a sphere
//! let found = kdtree.within_radius(&[2.0, 1.5, 2.5], 1.5);
//! assert_eq!(found.len(), 2);
//! assert!(found.iter().any(|&&p| p == [1.0, 2.0, 3.0]));
//! assert!(found.iter().any(|&&p| p == [3.0, 1.0, 2.0]));
//! ```
mod nalgebra;
mod nearest;
mod nearests;
mod sort;
mod tests;
mod within;
use nearest::*;
use nearests::*;
use sort::*;
use std::cmp::Ordering;
use std::marker::PhantomData;
use typenum::Unsigned;
use within::*;
/// A trait to represent k-dimensional point.
///
/// # Example
/// ```
/// struct MyItem {
/// point: [f64; 3],
/// id: usize,
/// }
/// impl kd_tree::KdPoint for MyItem {
/// type Scalar = f64;
/// type Dim = typenum::U3;
/// fn at(&self, k: usize) -> f64 { self.point[k] }
/// }
/// let kdtree: kd_tree::KdTree<MyItem> = kd_tree::KdTree::build_by_ordered_float(vec![
/// MyItem { point: [1.0, 2.0, 3.0], id: 111 },
/// MyItem { point: [3.0, 1.0, 2.0], id: 222 },
/// MyItem { point: [2.0, 3.0, 1.0], id: 333 },
/// ]);
/// assert_eq!(kdtree.nearest(&[3.1, 0.1, 2.2]).unwrap().item.id, 222);
/// ```
pub trait KdPoint {
type Scalar: num_traits::NumAssign + Copy + PartialOrd;
type Dim: Unsigned;
fn dim() -> usize {
<Self::Dim as Unsigned>::to_usize()
}
fn at(&self, i: usize) -> Self::Scalar;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ItemAndDistance<'a, T, Scalar> {
pub item: &'a T,
pub squared_distance: Scalar,
}
/// A slice of kd-tree.
/// This type implements [`std::ops::Deref`] to `[T]`.
/// This is an unsized type, meaning that it must always be used as a reference.
/// For an owned version of this type, see [`KdTree`].
#[derive(Debug, PartialEq, Eq)]
pub struct KdSliceN<T, N: Unsigned>(PhantomData<N>, [T]);
pub type KdSlice<T> = KdSliceN<T, <T as KdPoint>::Dim>;
impl<T, N: Unsigned> std::ops::Deref for KdSliceN<T, N> {
type Target = [T];
fn deref(&self) -> &[T] {
&self.1
}
}
impl<T: Clone, N: Unsigned> std::borrow::ToOwned for KdSliceN<T, N> {
type Owned = KdTreeN<T, N>;
fn to_owned(&self) -> Self::Owned {
KdTreeN(PhantomData, self.1.to_vec())
}
}
impl<T, N: Unsigned> KdSliceN<T, N> {
pub fn items(&self) -> &[T] {
&self.1
}
unsafe fn new_unchecked(items: &[T]) -> &Self {
&*(items as *const _ as *const Self)
}
/// # Example
/// ```
/// struct Item {
/// point: [i32; 3],
/// id: usize,
/// }
/// let mut items: Vec<Item> = vec![
/// Item { point: [1, 2, 3], id: 111 },
/// Item { point: [3, 1, 2], id: 222 },
/// Item { point: [2, 3, 1], id: 333 },
/// ];
/// let kdtree = kd_tree::KdSlice3::sort_by(&mut items, |item1, item2, k| item1.point[k].cmp(&item2.point[k]));
/// assert_eq!(kdtree.nearest_by(&[3, 1, 2], |item, k| item.point[k]).unwrap().item.id, 222);
/// ```
pub fn sort_by<F>(items: &mut [T], compare: F) -> &Self
where
F: Fn(&T, &T, usize) -> Ordering + Copy,
{
kd_sort_by(items, N::to_usize(), compare);
unsafe { Self::new_unchecked(items) }
}
/// # Example
/// ```
/// struct Item {
/// point: [f64; 3],
/// id: usize,
/// }
/// let mut items: Vec<Item> = vec![
/// Item { point: [1.0, 2.0, 3.0], id: 111 },
/// Item { point: [3.0, 1.0, 2.0], id: 222 },
/// Item { point: [2.0, 3.0, 1.0], id: 333 },
/// ];
/// use ordered_float::OrderedFloat;
/// let kdtree = kd_tree::KdSlice3::sort_by_key(&mut items, |item, k| OrderedFloat(item.point[k]));
/// assert_eq!(kdtree.nearest_by(&[3.1, 0.9, 2.1], |item, k| item.point[k]).unwrap().item.id, 222);
/// ```
pub fn sort_by_key<Key: Ord, F>(items: &mut [T], kd_key: F) -> &Self
where
F: Fn(&T, usize) -> Key + Copy,
{
Self::sort_by(items, |item1, item2, k| {
kd_key(item1, k).cmp(&kd_key(item2, k))
})
}
/// # Example
/// ```
/// use kd_tree::KdSlice;
/// let mut items: Vec<[f64; 3]> = vec![[1.0, 2.0, 3.0], [3.0, 1.0, 2.0], [2.0, 3.0, 1.0]];
/// let kdtree: &KdSlice<[f64; 3]> = KdSlice::sort_by_ordered_float(&mut items);
/// assert_eq!(kdtree.nearest(&[3.1, 0.9, 2.1]).unwrap().item, &[3.0, 1.0, 2.0]);
/// ```
pub fn sort_by_ordered_float(points: &mut [T]) -> &Self
where
T: KdPoint<Dim = N>,
T::Scalar: ordered_float::FloatCore,
{
Self::sort_by_key(points, |item, k| ordered_float::OrderedFloat(item.at(k)))
}
/// # Example
/// ```
/// use kd_tree::KdSlice;
/// let mut items: Vec<[i32; 3]> = vec![[1, 2, 3], [3, 1, 2], [2, 3, 1]];
/// let kdtree: &KdSlice<[i32; 3]> = KdSlice::sort(&mut items);
/// assert_eq!(kdtree.nearest(&[3, 1, 2]).unwrap().item, &[3, 1, 2]);
/// ```
pub fn sort(points: &mut [T]) -> &Self
where
T: KdPoint<Dim = N>,
T::Scalar: Ord,
{
Self::sort_by_key(points, |item, k| item.at(k))
}
/// Returns the nearest item from the input point. Returns `None` if `self.is_empty()`.
/// # Example
/// ```
/// struct Item {
/// point: [f64; 3],
/// id: usize,
/// }
/// let mut items: Vec<Item> = vec![
/// Item { point: [1.0, 2.0, 3.0], id: 111 },
/// Item { point: [3.0, 1.0, 2.0], id: 222 },
/// Item { point: [2.0, 3.0, 1.0], id: 333 },
/// ];
/// use ordered_float::OrderedFloat;
/// let kdtree = kd_tree::KdSlice3::sort_by_key(&mut items, |item, k| OrderedFloat(item.point[k]));
/// assert_eq!(kdtree.nearest_by(&[3.1, 0.9, 2.1], |item, k| item.point[k]).unwrap().item.id, 222);
/// ```
pub fn nearest_by<Q: KdPoint<Dim = N>>(
&self,
query: &Q,
coord: impl Fn(&T, usize) -> Q::Scalar + Copy,
) -> Option<ItemAndDistance<T, Q::Scalar>> {
if self.is_empty() {
None
} else {
Some(kd_nearest_by(self.items(), query, coord))
}
}
/// Returns the nearest item from the input point. Returns `None` if `self.is_empty()`.
/// # Example
/// ```
/// let mut items: Vec<[i32; 3]> = vec![[1, 2, 3], [3, 1, 2], [2, 3, 1]];
/// let kdtree = kd_tree::KdSlice::sort(&mut items);
/// assert_eq!(kdtree.nearest(&[3, 1, 2]).unwrap().item, &[3, 1, 2]);
/// ```
pub fn nearest(
&self,
query: &impl KdPoint<Scalar = T::Scalar, Dim = N>,
) -> Option<ItemAndDistance<T, T::Scalar>>
where
T: KdPoint<Dim = N>,
{
if self.is_empty() {
None
} else {
Some(kd_nearest(self.items(), query))
}
}
/*
/// # Example
/// ```
/// let kdtree = kd_tree::KdTree3::build(vec![[1, 2, 3], [3, 1, 2], [2, 3, 1]]);
/// let key = [3, 1, 2];
/// assert_eq!(kdtree.nearest_with(|p, k| key[k] - p[k]).item, &[3, 1, 2]);
/// ```
pub fn nearest_with<Scalar>(
&self,
kd_difference: impl Fn(&T, usize) -> Scalar + Copy,
) -> ItemAndDistance<T, Scalar>
where
Scalar: num_traits::NumAssign + Copy + PartialOrd,
{
kd_nearest_with(self.items(), N::to_usize(), kd_difference)
}
*/
/// Returns the nearest item from the input point. Returns `None` if `self.is_empty()`.
/// # Example
/// ```
/// struct Item {
/// point: [f64; 3],
/// id: usize,
/// }
/// let mut items: Vec<Item> = vec![
/// Item { point: [1.0, 2.0, 3.0], id: 111 },
/// Item { point: [3.0, 1.0, 2.0], id: 222 },
/// Item { point: [2.0, 3.0, 1.0], id: 333 },
/// ];
/// use ordered_float::OrderedFloat;
/// let kdtree = kd_tree::KdSlice3::sort_by_key(&mut items, |item, k| OrderedFloat(item.point[k]));
/// let nearests = kdtree.nearests_by(&[2.5, 2.0, 1.4], 2, |item, k| item.point[k]);
/// assert_eq!(nearests.len(), 2);
/// assert_eq!(nearests[0].item.id, 333);
/// assert_eq!(nearests[1].item.id, 222);
/// ```
pub fn nearests_by<Q: KdPoint<Dim = N>>(
&self,
query: &Q,
num: usize,
coord: impl Fn(&T, usize) -> Q::Scalar + Copy,
) -> Vec<ItemAndDistance<T, Q::Scalar>> {
kd_nearests_by(self.items(), query, num, coord)
}
/// Returns kNN(k nearest neighbors) from the input point.
/// # Example
/// ```
/// let mut items: Vec<[i32; 3]> = vec![[1, 2, 3], [3, 1, 2], [2, 3, 1], [3, 2, 2]];
/// let kdtree = kd_tree::KdSlice::sort(&mut items);
/// let nearests = kdtree.nearests(&[3, 1, 2], 2);
/// assert_eq!(nearests.len(), 2);
/// assert_eq!(nearests[0].item, &[3, 1, 2]);
/// assert_eq!(nearests[1].item, &[3, 2, 2]);
/// ```
pub fn nearests(
&self,
query: &impl KdPoint<Scalar = T::Scalar, Dim = N>,
num: usize,
) -> Vec<ItemAndDistance<T, T::Scalar>>
where
T: KdPoint<Dim = N>,
{
kd_nearests(self.items(), query, num)
}
pub fn within_by_cmp(&self, compare: impl Fn(&T, usize) -> Ordering + Copy) -> Vec<&T> {
kd_within_by_cmp(self, N::to_usize(), compare)
}
pub fn within_by<Q: KdPoint<Dim = N>>(
&self,
query: &[Q; 2],
coord: impl Fn(&T, usize) -> Q::Scalar + Copy,
) -> Vec<&T> {
assert!((0..Q::dim()).all(|k| query[0].at(k) <= query[1].at(k)));
self.within_by_cmp(|item, k| {
let a = coord(item, k);
if a < query[0].at(k) {
Ordering::Less
} else if a > query[1].at(k) {
Ordering::Greater
} else {
Ordering::Equal
}
})
}
/// search points within a rectangular region
/// # Example
/// ```
/// let mut items: Vec<[i32; 2]> = vec![[0, 0], [1, 0], [0, 1], [1, 1]];
/// let kdtree = kd_tree::KdSlice::sort(&mut items);
/// let within = kdtree.within(&[[1, 0], [2, 1]]);
/// assert_eq!(within.len(), 2);
/// assert!(within.contains(&&[1, 0]));
/// assert!(within.contains(&&[1, 1]));
/// ```
pub fn within(&self, query: &[impl KdPoint<Scalar = T::Scalar, Dim = N>; 2]) -> Vec<&T>
where
T: KdPoint<Dim = N>,
{
self.within_by(query, |item, k| item.at(k))
}
pub fn within_radius_by<Q: KdPoint<Dim = N>>(
&self,
query: &Q,
radius: Q::Scalar,
coord: impl Fn(&T, usize) -> Q::Scalar + Copy,
) -> Vec<&T> {
let mut results = self.within_by_cmp(|item, k| {
let coord = coord(item, k);
if coord < query.at(k) - radius {
Ordering::Less
} else if coord > query.at(k) + radius {
Ordering::Greater
} else {
Ordering::Equal
}
});
results.retain(|item| {
let mut distance = <Q::Scalar as num_traits::Zero>::zero();
for k in 0..N::to_usize() {
let diff = coord(item, k) - query.at(k);
distance += diff * diff;
}
distance < radius * radius
});
results
}
/// search points within k-dimensional sphere
pub fn within_radius(
&self,
query: &impl KdPoint<Scalar = T::Scalar, Dim = N>,
radius: T::Scalar,
) -> Vec<&T>
where
T: KdPoint<Dim = N>,
{
self.within_radius_by(query, radius, |item, k| item.at(k))
}
}
#[cfg(feature = "rayon")]
impl<T: Send, N: Unsigned> KdSliceN<T, N> {
/// Same as [`Self::sort_by`], but using multiple threads.
pub fn par_sort_by<F>(items: &mut [T], compare: F) -> &Self
where
F: Fn(&T, &T, usize) -> Ordering + Copy + Send,
{
kd_par_sort_by(items, N::to_usize(), compare);
unsafe { Self::new_unchecked(items) }
}
/// Same as [`Self::sort_by_key`], but using multiple threads.
pub fn par_sort_by_key<Key: Ord, F>(items: &mut [T], kd_key: F) -> &Self
where
F: Fn(&T, usize) -> Key + Copy + Send,
{
Self::par_sort_by(items, move |item1, item2, k| {
kd_key(item1, k).cmp(&kd_key(item2, k))
})
}
/// Same as [`Self::sort_by_ordered_float`], but using multiple threads.
pub fn par_sort_by_ordered_float(points: &mut [T]) -> &Self
where
T: KdPoint<Dim = N>,
T::Scalar: ordered_float::FloatCore,
{
Self::par_sort_by_key(points, |item, k| ordered_float::OrderedFloat(item.at(k)))
}
/// Same as [`Self::sort`], but using multiple threads.
pub fn par_sort(points: &mut [T]) -> &Self
where
T: KdPoint<Dim = N>,
T::Scalar: Ord,
{
Self::par_sort_by_key(points, |item, k| item.at(k))
}
}
/// An owned kd-tree.
/// This type implements [`std::ops::Deref`] to [`KdSlice`].
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct KdTreeN<T, N: Unsigned>(PhantomData<N>, Vec<T>);
pub type KdTree<T> = KdTreeN<T, <T as KdPoint>::Dim>;
impl<T, N: Unsigned> std::ops::Deref for KdTreeN<T, N> {
type Target = KdSliceN<T, N>;
fn deref(&self) -> &Self::Target {
unsafe { KdSliceN::new_unchecked(&self.1) }
}
}
impl<T, N: Unsigned> AsRef<KdSliceN<T, N>> for KdTreeN<T, N> {
fn as_ref(&self) -> &KdSliceN<T, N> {
self
}
}
impl<T, N: Unsigned> std::borrow::Borrow<KdSliceN<T, N>> for KdTreeN<T, N> {
fn borrow(&self) -> &KdSliceN<T, N> {
self
}
}
impl<T, N: Unsigned> From<KdTreeN<T, N>> for Vec<T> {
fn from(src: KdTreeN<T, N>) -> Self {
src.1
}
}
impl<T, N: Unsigned> KdTreeN<T, N> {
pub fn into_vec(self) -> Vec<T> {
self.1
}
/// # Example
/// ```
/// struct Item {
/// point: [i32; 3],
/// id: usize,
/// }
/// let kdtree = kd_tree::KdTree3::build_by(
/// vec![
/// Item { point: [1, 2, 3], id: 111 },
/// Item { point: [3, 1, 2], id: 222 },
/// Item { point: [2, 3, 1], id: 333 },
/// ],
/// |item1, item2, k| item1.point[k].cmp(&item2.point[k])
/// );
/// assert_eq!(kdtree.nearest_by(&[3, 1, 2], |item, k| item.point[k]).unwrap().item.id, 222);
/// ```
pub fn build_by<F>(mut items: Vec<T>, compare: F) -> Self
where
F: Fn(&T, &T, usize) -> Ordering + Copy,
{
kd_sort_by(&mut items, N::to_usize(), compare);
Self(PhantomData, items)
}
/// # Example
/// ```
/// struct Item {
/// point: [f64; 3],
/// id: usize,
/// }
/// let kdtree = kd_tree::KdTree3::build_by_key(
/// vec![
/// Item { point: [1.0, 2.0, 3.0], id: 111 },
/// Item { point: [3.0, 1.0, 2.0], id: 222 },
/// Item { point: [2.0, 3.0, 1.0], id: 333 },
/// ],
/// |item, k| ordered_float::OrderedFloat(item.point[k])
/// );
/// assert_eq!(kdtree.nearest_by(&[3.1, 0.9, 2.1], |item, k| item.point[k]).unwrap().item.id, 222);
/// ```
pub fn build_by_key<Key, F>(items: Vec<T>, kd_key: F) -> Self
where
Key: Ord,
F: Fn(&T, usize) -> Key + Copy,
{
Self::build_by(items, |item1, item2, k| {
kd_key(item1, k).cmp(&kd_key(item2, k))
})
}
/// # Example
/// ```
/// use kd_tree::KdTree;
/// let kdtree: KdTree<[f64; 3]> = KdTree::build_by_ordered_float(vec![
/// [1.0, 2.0, 3.0], [3.0, 1.0, 2.0], [2.0, 3.0, 1.0]
/// ]);
/// assert_eq!(kdtree.nearest(&[3.1, 0.9, 2.1]).unwrap().item, &[3.0, 1.0, 2.0]);
/// ```
pub fn build_by_ordered_float(points: Vec<T>) -> Self
where
T: KdPoint<Dim = N>,
T::Scalar: ordered_float::FloatCore,
{
Self::build_by_key(points, |item, k| ordered_float::OrderedFloat(item.at(k)))
}
/// # Example
/// ```
/// use kd_tree::KdTree;
/// let kdtree: KdTree<[i32; 3]> = KdTree::build(vec![[1, 2, 3], [3, 1, 2], [2, 3, 1]]);
/// assert_eq!(kdtree.nearest(&[3, 1, 2]).unwrap().item, &[3, 1, 2]);
/// ```
pub fn build(points: Vec<T>) -> Self
where
T: KdPoint<Dim = N>,
T::Scalar: Ord,
{
Self::build_by_key(points, |item, k| item.at(k))
}
}
#[cfg(feature = "serde")]
mod impl_serde {
use super::{KdTreeN, PhantomData, Unsigned};
impl<T: serde::Serialize, N: Unsigned> serde::Serialize for KdTreeN<T, N> {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
self.1.serialize(serializer)
}
}
impl<'de, T: serde::Deserialize<'de>, N: Unsigned> serde::Deserialize<'de> for KdTreeN<T, N> {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
Vec::<T>::deserialize(deserializer).map(|items| Self(PhantomData, items))
}
}
}
#[cfg(feature = "rayon")]
impl<T: Send, N: Unsigned> KdTreeN<T, N> {
/// Same as [`Self::build_by`], but using multiple threads.
pub fn par_build_by<F>(mut items: Vec<T>, compare: F) -> Self
where
F: Fn(&T, &T, usize) -> Ordering + Copy + Send,
{
kd_par_sort_by(&mut items, N::to_usize(), compare);
Self(PhantomData, items)
}
/// Same as [`Self::build_by_key`], but using multiple threads.
pub fn par_build_by_key<Key, F>(items: Vec<T>, kd_key: F) -> Self
where
Key: Ord,
F: Fn(&T, usize) -> Key + Copy + Send,
{
Self::par_build_by(items, move |item1, item2, k| {
kd_key(item1, k).cmp(&kd_key(item2, k))
})
}
/// Same as [`Self::build_by_ordered_float`], but using multiple threads.
pub fn par_build_by_ordered_float(points: Vec<T>) -> Self
where
T: KdPoint<Dim = N>,
T::Scalar: ordered_float::FloatCore,
{
Self::par_build_by_key(points, |item, k| ordered_float::OrderedFloat(item.at(k)))
}
/// Same as [`Self::build`], but using multiple threads.
pub fn par_build(points: Vec<T>) -> Self
where
T: KdPoint<Dim = N>,
T::Scalar: Ord,
{
Self::par_build_by_key(points, |item, k| item.at(k))
}
}
/// This type refers a slice of items, `[T]`, and contains kd-tree of indices to the items, `KdTree<usize, N>`.
/// Unlike [`KdSliceN::sort`], [`KdIndexTreeN::build`] doesn't sort input items.
/// ```
/// let items = vec![[1, 2, 3], [3, 1, 2], [2, 3, 1]];
/// let kdtree = kd_tree::KdIndexTree::build(&items);
/// assert_eq!(kdtree.nearest(&[3, 1, 2]).unwrap().item, &1); // nearest() returns an index of items.
/// ```
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct KdIndexTreeN<'a, T, N: Unsigned> {
source: &'a [T],
kdtree: KdTreeN<usize, N>,
}
pub type KdIndexTree<'a, T> = KdIndexTreeN<'a, T, <T as KdPoint>::Dim>;
impl<'a, T, N: Unsigned> KdIndexTreeN<'a, T, N> {
pub fn source(&self) -> &'a [T] {
self.source
}
pub fn indices(&self) -> &KdSliceN<usize, N> {
&self.kdtree
}
pub fn item(&self, i: usize) -> &'a T {
&self.source[i]
}
pub fn build_by<F>(source: &'a [T], compare: F) -> Self
where
F: Fn(&T, &T, usize) -> Ordering + Copy,
{
Self {
source,
kdtree: KdTreeN::build_by((0..source.len()).collect(), |i1, i2, k| {
compare(&source[*i1], &source[*i2], k)
}),
}
}
pub fn build_by_key<Key, F>(source: &'a [T], kd_key: F) -> Self
where
Key: Ord,
F: Fn(&T, usize) -> Key + Copy,
{
Self::build_by(source, |item1, item2, k| {
kd_key(item1, k).cmp(&kd_key(item2, k))
})
}
pub fn build_by_ordered_float(points: &'a [T]) -> Self
where
T: KdPoint<Dim = N>,
T::Scalar: ordered_float::FloatCore,
{
Self::build_by_key(points, |item, k| ordered_float::OrderedFloat(item.at(k)))
}
pub fn build(points: &'a [T]) -> Self
where
T: KdPoint<Dim = N>,
T::Scalar: Ord,
{
Self::build_by_key(points, |item, k| item.at(k))
}
pub fn nearest_by<Q: KdPoint<Dim = N>>(
&self,
query: &Q,
coord: impl Fn(&T, usize) -> Q::Scalar + Copy,
) -> Option<ItemAndDistance<usize, Q::Scalar>> {
self.kdtree
.nearest_by(query, |&index, k| coord(&self.source[index], k))
}
/// # Example
/// ```
/// let mut items: Vec<[i32; 3]> = vec![[1, 2, 3], [3, 1, 2], [2, 3, 1]];
/// let kdtree = kd_tree::KdIndexTree3::build(&items);
/// assert_eq!(kdtree.nearest(&[3, 1, 2]).unwrap().item, &1);
/// ```
pub fn nearest(
&self,
query: &impl KdPoint<Scalar = T::Scalar, Dim = N>,
) -> Option<ItemAndDistance<usize, T::Scalar>>
where
T: KdPoint<Dim = N>,
{
self.nearest_by(query, |item, k| item.at(k))
}
pub fn nearests_by<Q: KdPoint<Dim = N>>(
&self,
query: &Q,
num: usize,
coord: impl Fn(&T, usize) -> Q::Scalar + Copy,
) -> Vec<ItemAndDistance<usize, Q::Scalar>> {
self.kdtree
.nearests_by(query, num, |&index, k| coord(&self.source[index], k))
}
/// Returns kNN(k nearest neighbors) from the input point.
/// # Example
/// ```
/// let mut items: Vec<[i32; 3]> = vec![[1, 2, 3], [3, 1, 2], [2, 3, 1], [3, 2, 2]];
/// let kdtree = kd_tree::KdIndexTree::build(&mut items);
/// let nearests = kdtree.nearests(&[3, 1, 2], 2);
/// assert_eq!(nearests.len(), 2);
/// assert_eq!(nearests[0].item, &1);
/// assert_eq!(nearests[1].item, &3);
/// ```
pub fn nearests(
&self,
query: &impl KdPoint<Scalar = T::Scalar, Dim = N>,
num: usize,
) -> Vec<ItemAndDistance<usize, T::Scalar>>
where
T: KdPoint<Dim = N>,
{
self.nearests_by(query, num, |item, k| item.at(k))
}
pub fn within_by_cmp(&self, compare: impl Fn(&T, usize) -> Ordering + Copy) -> Vec<&usize> {
self.kdtree
.within_by_cmp(|&index, k| compare(&self.source[index], k))
}
pub fn within_by<Q: KdPoint<Dim = N>>(
&self,
query: &[Q; 2],
coord: impl Fn(&T, usize) -> Q::Scalar + Copy,
) -> Vec<&usize> {
self.kdtree
.within_by(query, |&index, k| coord(&self.source[index], k))
}
pub fn within(&self, query: &[impl KdPoint<Scalar = T::Scalar, Dim = N>; 2]) -> Vec<&usize>
where
T: KdPoint<Dim = N>,
{
self.within_by(query, |item, k| item.at(k))
}
pub fn within_radius_by<Q: KdPoint<Dim = N>>(
&self,
query: &Q,
radius: Q::Scalar,
coord: impl Fn(&T, usize) -> Q::Scalar + Copy,
) -> Vec<&usize> {
self.kdtree
.within_radius_by(query, radius, |&index, k| coord(&self.source[index], k))
}
pub fn within_radius(
&self,
query: &impl KdPoint<Scalar = T::Scalar, Dim = N>,
radius: T::Scalar,
) -> Vec<&usize>
where
T: KdPoint<Dim = N>,
{
self.within_radius_by(query, radius, |item, k| item.at(k))
}
}
#[cfg(feature = "rayon")]
impl<'a, T: Sync, N: Unsigned> KdIndexTreeN<'a, T, N> {
pub fn par_build_by<F>(source: &'a [T], compare: F) -> Self
where
F: Fn(&T, &T, usize) -> Ordering + Copy + Send,
{
Self {
source,
kdtree: KdTreeN::par_build_by((0..source.len()).collect(), move |i1, i2, k| {
compare(&source[*i1], &source[*i2], k)
}),
}
}
pub fn par_build_by_key<Key, F>(source: &'a [T], kd_key: F) -> Self
where
Key: Ord,
F: Fn(&T, usize) -> Key + Copy + Send,
{
Self::par_build_by(source, move |item1, item2, k| {
kd_key(item1, k).cmp(&kd_key(item2, k))
})
}
pub fn par_build_by_ordered_float(points: &'a [T]) -> Self
where
T: KdPoint<Dim = N>,
T::Scalar: ordered_float::FloatCore,
{
Self::par_build_by_key(points, |item, k| ordered_float::OrderedFloat(item.at(k)))
}
pub fn par_build(points: &'a [T]) -> Self
where
T: KdPoint<Dim = N>,
T::Scalar: Ord,
{
Self::par_build_by_key(points, |item, k| item.at(k))
}
}
macro_rules! define_kdtree_aliases {
($($dim:literal),*) => {
$(
paste::paste! {
pub type [<KdSlice $dim>]<T> = KdSliceN<T, typenum::[<U $dim>]>;
pub type [<KdTree $dim>]<T> = KdTreeN<T, typenum::[<U $dim>]>;
pub type [<KdIndexTree $dim>]<'a, T> = KdIndexTreeN<'a, T, typenum::[<U $dim>]>;
}
)*
};
}
define_kdtree_aliases!(1, 2, 3, 4, 5, 6, 7, 8);
macro_rules! impl_kd_points {
($($len:literal),*) => {
$(
paste::paste!{
impl<T: num_traits::NumAssign + Copy + PartialOrd> KdPoint for [T; $len] {
type Scalar = T;
type Dim = typenum::[<U $len>];
fn at(&self, i: usize) -> T { self[i] }
}
}
)*
};
}
impl_kd_points!(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
impl<P: KdPoint, T> KdPoint for (P, T) {
type Scalar = P::Scalar;
type Dim = P::Dim;
fn at(&self, k: usize) -> Self::Scalar {
self.0.at(k)
}
}
/// kd-tree of key-value pairs.
/// ```
/// let kdmap: kd_tree::KdMap<[isize; 3], &'static str> = kd_tree::KdMap::build(vec![
/// ([1, 2, 3], "foo"),
/// ([2, 3, 1], "bar"),
/// ([3, 1, 2], "buzz"),
/// ]);
/// assert_eq!(kdmap.nearest(&[3, 1, 2]).unwrap().item.1, "buzz");
/// ```
pub type KdMap<P, T> = KdTree<(P, T)>;
/// kd-tree slice of key-value pairs.
/// ```
/// let mut items: Vec<([isize; 3], &'static str)> = vec![
/// ([1, 2, 3], "foo"),
/// ([2, 3, 1], "bar"),
/// ([3, 1, 2], "buzz"),
/// ];
/// let kdmap = kd_tree::KdMapSlice::sort(&mut items);
/// assert_eq!(kdmap.nearest(&[3, 1, 2]).unwrap().item.1, "buzz");
/// ```
pub type KdMapSlice<P, T> = KdSlice<(P, T)>;

44
vendor/kd-tree/src/nalgebra.rs vendored Normal file
View File

@@ -0,0 +1,44 @@
#![cfg(feature = "nalgebra")]
use super::KdPoint;
macro_rules! impl_kdpoint_for_nalgebra_point {
($($dim:literal),*) => {
$(
paste::paste! {
impl<Scalar> KdPoint for nalgebra::Point<Scalar, $dim>
where
Scalar: num_traits::NumAssign + Copy + PartialOrd + nalgebra::Scalar,
{
type Scalar = Scalar;
type Dim = typenum::[<U $dim>];
fn at(&self, k: usize) -> Scalar {
self[k]
}
}
}
)*
};
}
macro_rules! impl_kdpoint_for_nalgebra_vector {
($($dim:literal),*) => {
$(
paste::paste! {
impl<Scalar, Storage> KdPoint for nalgebra::Vector<Scalar, nalgebra::Const<$dim>, Storage>
where
Scalar: num_traits::NumAssign + Copy + PartialOrd + nalgebra::Scalar,
Storage: nalgebra::StorageMut<Scalar, nalgebra::Const<$dim>>
{
type Scalar = Scalar;
type Dim = typenum::[<U $dim>];
fn at(&self, k: usize) -> Scalar {
self[k]
}
}
}
)*
};
}
impl_kdpoint_for_nalgebra_point!(1, 2, 3, 4, 5, 6, 7, 8);
impl_kdpoint_for_nalgebra_vector!(1, 2, 3, 4, 5, 6, 7, 8);

134
vendor/kd-tree/src/nearest.rs vendored Normal file
View File

@@ -0,0 +1,134 @@
use crate::{ItemAndDistance, KdPoint};
pub fn kd_nearest<'a, T: KdPoint>(
kdtree: &'a [T],
query: &impl KdPoint<Scalar = T::Scalar, Dim = T::Dim>,
) -> ItemAndDistance<'a, T, T::Scalar> {
kd_nearest_by(kdtree, query, |item, k| item.at(k))
}
pub fn kd_nearest_by<'a, T, P: KdPoint>(
kdtree: &'a [T],
query: &P,
get: impl Fn(&T, usize) -> P::Scalar + Copy,
) -> ItemAndDistance<'a, T, P::Scalar> {
fn distance_squared<P: KdPoint, T>(
p1: &P,
p2: &T,
get: impl Fn(&T, usize) -> P::Scalar,
) -> P::Scalar {
let mut squared_distance = <P::Scalar as num_traits::Zero>::zero();
for i in 0..P::dim() {
let diff = p1.at(i) - get(p2, i);
squared_distance += diff * diff;
}
squared_distance
}
fn recurse<'a, T, Q: KdPoint>(
nearest: &mut ItemAndDistance<'a, T, Q::Scalar>,
kdtree: &'a [T],
get: impl Fn(&T, usize) -> Q::Scalar + Copy,
query: &Q,
axis: usize,
) {
let mid_idx = kdtree.len() / 2;
let item = &kdtree[mid_idx];
let squared_distance = distance_squared(query, item, get);
if squared_distance < nearest.squared_distance {
nearest.item = item;
nearest.squared_distance = squared_distance;
use num_traits::Zero;
if nearest.squared_distance.is_zero() {
return;
}
}
let mid_pos = get(item, axis);
let [branch1, branch2] = if query.at(axis) < mid_pos {
[&kdtree[..mid_idx], &kdtree[mid_idx + 1..]]
} else {
[&kdtree[mid_idx + 1..], &kdtree[..mid_idx]]
};
if !branch1.is_empty() {
recurse(nearest, branch1, get, query, (axis + 1) % Q::dim());
}
if !branch2.is_empty() {
let diff = query.at(axis) - mid_pos;
if diff * diff < nearest.squared_distance {
recurse(nearest, branch2, get, query, (axis + 1) % Q::dim());
}
}
}
assert!(!kdtree.is_empty());
let mut nearest = ItemAndDistance {
item: &kdtree[0],
squared_distance: distance_squared(query, &kdtree[0], get),
};
recurse(&mut nearest, kdtree, get, query, 0);
nearest
}
#[allow(dead_code)]
pub fn kd_nearest_with<T, Scalar>(
kdtree: &[T],
dim: usize,
kd_difference: impl Fn(&T, usize) -> Scalar + Copy,
) -> ItemAndDistance<T, Scalar>
where
Scalar: num_traits::NumAssign + Copy + PartialOrd,
{
fn squared_distance<T, Scalar: num_traits::NumAssign + Copy>(
item: &T,
dim: usize,
kd_difference: impl Fn(&T, usize) -> Scalar + Copy,
) -> Scalar {
let mut squared_distance = Scalar::zero();
for k in 0..dim {
let diff = kd_difference(item, k);
squared_distance += diff * diff;
}
squared_distance
}
fn recurse<'a, T, Scalar>(
nearest: &mut ItemAndDistance<'a, T, Scalar>,
kdtree: &'a [T],
axis: usize,
dim: usize,
kd_difference: impl Fn(&T, usize) -> Scalar + Copy,
) where
Scalar: num_traits::NumAssign + Copy + PartialOrd,
{
let mid_idx = kdtree.len() / 2;
let mid = &kdtree[mid_idx];
let squared_distance = squared_distance(mid, dim, kd_difference);
if squared_distance < nearest.squared_distance {
*nearest = ItemAndDistance {
item: mid,
squared_distance,
};
if nearest.squared_distance.is_zero() {
return;
}
}
let [branch1, branch2] = if kd_difference(mid, axis) < Scalar::zero() {
[&kdtree[..mid_idx], &kdtree[mid_idx + 1..]]
} else {
[&kdtree[mid_idx + 1..], &kdtree[..mid_idx]]
};
if !branch1.is_empty() {
recurse(nearest, branch1, (axis + 1) % dim, dim, kd_difference);
}
if !branch2.is_empty() {
let diff = kd_difference(mid, axis);
if diff * diff < nearest.squared_distance {
recurse(nearest, branch2, (axis + 1) % dim, dim, kd_difference);
}
}
}
assert!(!kdtree.is_empty());
let mut nearest = ItemAndDistance {
item: &kdtree[0],
squared_distance: squared_distance(&kdtree[0], dim, kd_difference),
};
recurse(&mut nearest, kdtree, 0, dim, kd_difference);
nearest
}

82
vendor/kd-tree/src/nearests.rs vendored Normal file
View File

@@ -0,0 +1,82 @@
use crate::{ItemAndDistance, KdPoint};
pub fn kd_nearests<'a, T: KdPoint>(
kdtree: &'a [T],
query: &impl KdPoint<Scalar = T::Scalar, Dim = T::Dim>,
num: usize,
) -> Vec<ItemAndDistance<'a, T, T::Scalar>> {
kd_nearests_by(kdtree, query, num, |item, k| item.at(k))
}
pub fn kd_nearests_by<'a, T, P: KdPoint>(
kdtree: &'a [T],
query: &P,
num: usize,
get: impl Fn(&T, usize) -> P::Scalar + Copy,
) -> Vec<ItemAndDistance<'a, T, P::Scalar>> {
fn distance_squared<P: KdPoint, T>(
p1: &P,
p2: &T,
get: impl Fn(&T, usize) -> P::Scalar,
) -> P::Scalar {
let mut squared_distance = <P::Scalar as num_traits::Zero>::zero();
for i in 0..P::dim() {
let diff = p1.at(i) - get(p2, i);
squared_distance += diff * diff;
}
squared_distance
}
fn recurse<'a, T, Q: KdPoint>(
nearests: &mut Vec<ItemAndDistance<'a, T, Q::Scalar>>,
kdtree: &'a [T],
get: impl Fn(&T, usize) -> Q::Scalar + Copy,
query: &Q,
axis: usize,
) {
let mid_idx = kdtree.len() / 2;
let item = &kdtree[mid_idx];
let squared_distance = distance_squared(query, item, get);
if nearests.len() < nearests.capacity()
|| squared_distance < nearests.last().unwrap().squared_distance
{
if nearests.len() == nearests.capacity() {
nearests.pop();
}
let i = nearests
.binary_search_by(|item| {
item.squared_distance
.partial_cmp(&squared_distance)
.unwrap_or(std::cmp::Ordering::Equal)
})
.unwrap_or_else(|i| i);
nearests.insert(
i,
ItemAndDistance {
item,
squared_distance,
},
);
}
let mid_pos = get(item, axis);
let [branch1, branch2] = if query.at(axis) < mid_pos {
[&kdtree[..mid_idx], &kdtree[mid_idx + 1..]]
} else {
[&kdtree[mid_idx + 1..], &kdtree[..mid_idx]]
};
if !branch1.is_empty() {
recurse(nearests, branch1, get, query, (axis + 1) % Q::dim());
}
if !branch2.is_empty() {
let diff = query.at(axis) - mid_pos;
if diff * diff < nearests.last().unwrap().squared_distance {
recurse(nearests, branch2, get, query, (axis + 1) % Q::dim());
}
}
}
if num == 0 || kdtree.is_empty() {
return Vec::new();
}
let mut nearests = Vec::with_capacity(num);
recurse(&mut nearests, kdtree, get, query, 0);
nearests
}

49
vendor/kd-tree/src/sort.rs vendored Normal file
View File

@@ -0,0 +1,49 @@
use std::cmp::Ordering;
pub fn kd_sort_by<T>(
items: &mut [T],
dim: usize,
kd_compare: impl Fn(&T, &T, usize) -> Ordering + Copy,
) {
fn recurse<T>(
items: &mut [T],
axis: usize,
dim: usize,
kd_compare: impl Fn(&T, &T, usize) -> Ordering + Copy,
) {
if items.len() >= 2 {
items.select_nth_unstable_by(items.len() / 2, |x, y| kd_compare(x, y, axis));
let mid = items.len() / 2;
let axis = (axis + 1) % dim;
recurse(&mut items[..mid], axis, dim, kd_compare);
recurse(&mut items[mid + 1..], axis, dim, kd_compare);
}
}
recurse(items, 0, dim, kd_compare);
}
#[cfg(feature = "rayon")]
pub fn kd_par_sort_by<T: Send>(
items: &mut [T],
dim: usize,
kd_compare: impl Fn(&T, &T, usize) -> Ordering + Copy + Send,
) {
fn recurse<T: Send>(
items: &mut [T],
axis: usize,
dim: usize,
kd_compare: impl Fn(&T, &T, usize) -> Ordering + Copy + Send,
) {
if items.len() >= 2 {
items.select_nth_unstable_by(items.len() / 2, |x, y| kd_compare(x, y, axis));
let mid = items.len() / 2;
let axis = (axis + 1) % dim;
let (lhs, rhs) = items.split_at_mut(mid);
rayon::join(
move || recurse(lhs, axis, dim, kd_compare),
move || recurse(&mut rhs[1..], axis, dim, kd_compare),
);
}
}
recurse(items, 0, dim, kd_compare);
}

207
vendor/kd-tree/src/tests.rs vendored Normal file
View File

@@ -0,0 +1,207 @@
#![cfg(test)]
use super::*;
#[test]
fn test_nearest() {
let mut gen3d = random3d_generator();
let kdtree = KdTree::build_by_ordered_float(vec(10000, |_| gen3d()));
for _ in 0..100 {
let query = gen3d();
let found = kdtree.nearest(&query).unwrap().item;
let expected = kdtree
.iter()
.min_by_key(|p| ordered_float::OrderedFloat(squared_distance(p, &query)))
.unwrap();
assert_eq!(found, expected);
}
}
#[test]
fn test_nearests() {
test_nearests_by(random3d_generator());
test_nearests_by(random3d_10th_generator());
}
fn test_nearests_by(mut gen3d: impl FnMut() -> [f64; 3]) {
let kdtree = KdTree::build_by_ordered_float(vec(10000, |_| gen3d()));
const NUM: usize = 5;
for _ in 0..100 {
let query = gen3d();
let neighborhood = kdtree.nearests(&query, NUM);
assert_eq!(neighborhood.len(), NUM);
for i in 1..neighborhood.len() {
assert!(neighborhood[i - 1].squared_distance <= neighborhood[i].squared_distance);
}
let neighborhood_radius = neighborhood
.iter()
.max_by_key(|entry| ordered_float::OrderedFloat(entry.squared_distance))
.unwrap()
.squared_distance;
let neighborhood_contains = |p: &[f64; 3]| {
neighborhood
.iter()
.any(|entry| std::ptr::eq(entry.item as _, p as _))
};
assert!(kdtree.iter().all(
|p| neighborhood_contains(p) || neighborhood_radius <= squared_distance(p, &query)
));
}
}
#[test]
fn test_within() {
let mut gen3d = random3d_generator();
let kdtree = KdTree::build_by_ordered_float(vec(10000, |_| gen3d()));
for _ in 0..100 {
let mut p1 = gen3d();
let mut p2 = gen3d();
for k in 0..3 {
if p1[k] > p2[k] {
std::mem::swap(&mut p1[k], &mut p2[k]);
}
}
let found = kdtree.within(&[p1, p2]);
let count = kdtree
.iter()
.filter(|p| (0..3).all(|k| p1[k] <= p[k] && p[k] <= p2[k]))
.count();
assert_eq!(found.len(), count);
}
}
#[test]
fn test_within_against_empty() {
let empty: KdTree<[f64; 3]> = KdTree::build_by_ordered_float(vec![]);
assert!(empty.within(&[[0.0, 0.0, 0.0], [1.0, 1.0, 1.0]]).is_empty());
}
#[test]
fn test_within_radius() {
let mut gen3d = random3d_generator();
let kdtree = KdTree::build_by_ordered_float(vec(10000, |_| gen3d()));
const RADIUS: f64 = 0.1;
for _ in 0..100 {
let query = gen3d();
let found = kdtree.within_radius(&query, RADIUS);
let count = kdtree
.iter()
.filter(|p| squared_distance(p, &query) < RADIUS * RADIUS)
.count();
assert_eq!(found.len(), count);
}
}
fn squared_distance<T: num_traits::Num + Copy>(p1: &[T; 3], p2: &[T; 3]) -> T {
let dx = p1[0] - p2[0];
let dy = p1[1] - p2[1];
let dz = p1[2] - p2[2];
dx * dx + dy * dy + dz * dz
}
fn random3d_generator() -> impl FnMut() -> [f64; 3] {
use rand::Rng;
let mut rng = rand::rng();
move || [rng.random(), rng.random(), rng.random()]
}
fn random3d_10th_generator() -> impl FnMut() -> [f64; 3] {
// generates a random number between 0 and 1 with 0.1 step
fn random_10th(rng: &mut impl rand::Rng) -> f64 {
f64::from(rng.random_range(0u8..=10u8)) / 10.0
}
let mut rng = rand::rng();
move || {
[
random_10th(&mut rng),
random_10th(&mut rng),
random_10th(&mut rng),
]
}
}
fn vec<T>(count: usize, mut f: impl FnMut(usize) -> T) -> Vec<T> {
let mut items = Vec::with_capacity(count);
for i in 0..count {
items.push(f(i));
}
items
}
#[cfg(feature = "nalgebra")]
#[test]
fn test_nalgebra_point() {
use ::nalgebra as na;
let mut gen3d = random3d_generator();
let kdtree: KdTree<na::Point3<f64>> =
KdTree::build_by_ordered_float(vec(10000, |_| gen3d().into()));
for _ in 0..100 {
let query: na::Point3<f64> = gen3d().into();
let found = kdtree.nearest(&query).unwrap().item;
let expected = kdtree
.iter()
.min_by_key(|p| ordered_float::OrderedFloat((query - **p).norm()))
.unwrap();
assert_eq!(found, expected);
}
}
#[cfg(feature = "nalgebra")]
#[test]
fn test_nalgebra_vector() {
use ::nalgebra as na;
let mut gen3d = random3d_generator();
let kdtree: KdTree<na::Vector3<f64>> =
KdTree::build_by_ordered_float(vec(10000, |_| gen3d().into()));
for _ in 0..100 {
let query: na::Vector3<f64> = gen3d().into();
let found = kdtree.nearest(&query).unwrap().item;
let expected = kdtree
.iter()
.min_by_key(|p| ordered_float::OrderedFloat((query - **p).norm()))
.unwrap();
assert_eq!(found, expected);
}
}
#[cfg(feature = "serde")]
#[test]
fn test_serde() {
let src: KdTree3<[i32; 3]> = KdTree::build(vec![[1, 2, 3], [4, 5, 6]]);
let json = serde_json::to_string(&src).unwrap();
assert_eq!(json, "[[1,2,3],[4,5,6]]");
let dst: KdTree3<[i32; 3]> = serde_json::from_str(&json).unwrap();
assert_eq!(src, dst);
}
#[cfg(feature = "nalgebra-serde")]
#[test]
fn test_nalgebra_serde() {
use ::nalgebra as na;
let src: KdTree<na::Point3<f64>> = KdTree::build_by_ordered_float(vec![
na::Point3::new(1.0, 2.0, 3.0),
na::Point3::new(4.0, 5.0, 6.0),
]);
let json = serde_json::to_string(&src).unwrap();
assert_eq!(json, "[[1.0,2.0,3.0],[4.0,5.0,6.0]]");
let dst: KdTree3<na::Point3<f64>> = serde_json::from_str(&json).unwrap();
assert_eq!(src, dst);
}
#[cfg(feature = "rayon")]
#[test]
fn test_rayon() {
let points = {
let mut gen3d = random3d_generator();
vec(1000, |_| gen3d())
};
let kdtree1 = KdTree::build_by_ordered_float(points.clone());
let kdtree2 = KdTree::par_build_by_ordered_float(points.clone());
assert_eq!(kdtree1, kdtree2);
}

42
vendor/kd-tree/src/within.rs vendored Normal file
View File

@@ -0,0 +1,42 @@
use std::cmp::Ordering;
pub fn kd_within_by_cmp<T>(
kdtree: &[T],
dim: usize,
compare: impl Fn(&T, usize) -> Ordering + Copy,
) -> Vec<&T> {
fn recurse<'a, T>(
results: &mut Vec<&'a T>,
kdtree: &'a [T],
axis: usize,
dim: usize,
compare: impl Fn(&T, usize) -> Ordering + Copy,
) {
if kdtree.is_empty() {
return;
}
let axis = axis % dim;
let (lower, item, upper) = {
let mid = kdtree.len() / 2;
(&kdtree[..mid], &kdtree[mid], &kdtree[mid + 1..])
};
match compare(item, axis) {
Ordering::Equal => {
if (1..dim).all(|k| compare(item, (axis + k) % dim) == Ordering::Equal) {
results.push(item);
}
recurse(results, lower, axis + 1, dim, compare);
recurse(results, upper, axis + 1, dim, compare);
}
Ordering::Less => {
recurse(results, upper, axis + 1, dim, compare);
}
Ordering::Greater => {
recurse(results, lower, axis + 1, dim, compare);
}
}
}
let mut results = Vec::new();
recurse(&mut results, kdtree, 0, dim, compare);
results
}