mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Update kiddo from 0.2 to 4.2.0
This commit is contained in:
parent
a168ea8dcd
commit
7edbb4449e
98
Cargo.lock
generated
98
Cargo.lock
generated
@ -450,6 +450,12 @@ dependencies = [
|
|||||||
"tower-service",
|
"tower-service",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "az"
|
||||||
|
version = "1.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "backtrace"
|
name = "backtrace"
|
||||||
version = "0.3.71"
|
version = "0.3.71"
|
||||||
@ -1842,6 +1848,12 @@ dependencies = [
|
|||||||
"syn 2.0.65",
|
"syn 2.0.65",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "divrem"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "69dde51e8fef5e12c1d65e0929b03d66e4c0c18282bc30ed2ca050ad6f44dd82"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dlib"
|
name = "dlib"
|
||||||
version = "0.5.2"
|
version = "0.5.2"
|
||||||
@ -1851,6 +1863,12 @@ dependencies = [
|
|||||||
"libloading 0.8.3",
|
"libloading 0.8.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "doc-comment"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dot_vox"
|
name = "dot_vox"
|
||||||
version = "5.1.1"
|
version = "5.1.1"
|
||||||
@ -1930,6 +1948,12 @@ version = "1.12.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b"
|
checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "elapsed"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6f4e5af126dafd0741c2ad62d47f68b28602550102e5f0dd45c8a97fc8b49c29"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "emath"
|
name = "emath"
|
||||||
version = "0.23.0"
|
version = "0.23.0"
|
||||||
@ -2166,6 +2190,19 @@ version = "0.3.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9f6d018fb95a0b59f854aed68ecd96ce2b80af7911b92b1fed3c4b1fa516b91b"
|
checksum = "9f6d018fb95a0b59f854aed68ecd96ce2b80af7911b92b1fed3c4b1fa516b91b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fixed"
|
||||||
|
version = "1.27.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2fc715d38bea7b5bf487fcd79bcf8c209f0b58014f3018a7a19c2b855f472048"
|
||||||
|
dependencies = [
|
||||||
|
"az",
|
||||||
|
"bytemuck",
|
||||||
|
"half",
|
||||||
|
"num-traits",
|
||||||
|
"typenum",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fixedbitset"
|
name = "fixedbitset"
|
||||||
version = "0.1.9"
|
version = "0.1.9"
|
||||||
@ -2445,6 +2482,19 @@ dependencies = [
|
|||||||
"serde_json",
|
"serde_json",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "generator"
|
||||||
|
version = "0.7.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"rustversion",
|
||||||
|
"windows 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "generator"
|
name = "generator"
|
||||||
version = "0.8.1"
|
version = "0.8.1"
|
||||||
@ -3157,6 +3207,12 @@ version = "2.0.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5"
|
checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "init_with"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0175f63815ce00183bf755155ad0cb48c65226c5d17a724e369c25418d2b7699"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "inline_tweak"
|
name = "inline_tweak"
|
||||||
version = "1.1.1"
|
version = "1.1.1"
|
||||||
@ -3433,11 +3489,25 @@ checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kiddo"
|
name = "kiddo"
|
||||||
version = "0.2.5"
|
version = "4.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "06ced2e69cfc5f22f86ccc9ce4ecff9f19917f3083a4bac0f402bdab034d73f1"
|
checksum = "9d2f8d9e1bc7c6919ad2cdc83472a9a4b5ed2ea2c5392c9514fdf958a7920f9a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"az",
|
||||||
|
"divrem",
|
||||||
|
"doc-comment",
|
||||||
|
"elapsed",
|
||||||
|
"fixed",
|
||||||
|
"generator 0.7.5",
|
||||||
|
"init_with",
|
||||||
|
"itertools 0.12.1",
|
||||||
|
"log",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
|
"ordered-float 4.2.0",
|
||||||
|
"sorted-vec",
|
||||||
|
"tracing",
|
||||||
|
"tracing-subscriber",
|
||||||
|
"ubyte",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3620,7 +3690,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca"
|
checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
"generator",
|
"generator 0.8.1",
|
||||||
"scoped-tls",
|
"scoped-tls",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
@ -6132,6 +6202,12 @@ dependencies = [
|
|||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sorted-vec"
|
||||||
|
version = "0.8.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c6734caf0b6f51addd5eeacca12fb39b2c6c14e8d4f3ac42f3a78955c0467458"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "specs"
|
name = "specs"
|
||||||
version = "0.20.0"
|
version = "0.20.0"
|
||||||
@ -6880,6 +6956,12 @@ version = "1.17.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ubyte"
|
||||||
|
version = "0.10.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f720def6ce1ee2fc44d40ac9ed6d3a59c361c80a75a7aa8e75bb9baed31cf2ea"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unic-langid"
|
name = "unic-langid"
|
||||||
version = "0.9.5"
|
version = "0.9.5"
|
||||||
@ -7559,6 +7641,7 @@ dependencies = [
|
|||||||
"enum-map",
|
"enum-map",
|
||||||
"enumset",
|
"enumset",
|
||||||
"fallible-iterator",
|
"fallible-iterator",
|
||||||
|
"fixed",
|
||||||
"flate2",
|
"flate2",
|
||||||
"fxhash",
|
"fxhash",
|
||||||
"hashbrown 0.13.2",
|
"hashbrown 0.13.2",
|
||||||
@ -8536,6 +8619,15 @@ dependencies = [
|
|||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets 0.48.5",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows"
|
name = "windows"
|
||||||
version = "0.51.1"
|
version = "0.51.1"
|
||||||
|
@ -65,7 +65,7 @@ csv = { version = "1.1.3", optional = true }
|
|||||||
# graphviz exporters
|
# graphviz exporters
|
||||||
petgraph = { version = "0.6", optional = true }
|
petgraph = { version = "0.6", optional = true }
|
||||||
# K-d trees used for RRT pathfinding
|
# K-d trees used for RRT pathfinding
|
||||||
kiddo = { version = "0.2", optional = true }
|
kiddo = { version = "4.2.0", optional = true }
|
||||||
clap = { workspace = true, optional = true }
|
clap = { workspace = true, optional = true }
|
||||||
|
|
||||||
# Data structures
|
# Data structures
|
||||||
|
@ -8,9 +8,12 @@ use hashbrown::hash_map::DefaultHashBuilder;
|
|||||||
#[cfg(feature = "rrt_pathfinding")]
|
#[cfg(feature = "rrt_pathfinding")]
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
#[cfg(feature = "rrt_pathfinding")]
|
#[cfg(feature = "rrt_pathfinding")]
|
||||||
use kiddo::{distance::squared_euclidean, KdTree}; // For RRT paths (disabled for now)
|
use kiddo::{float::kdtree::KdTree, nearest_neighbour::NearestNeighbour, SquaredEuclidean}; /* For RRT paths (disabled for now) */
|
||||||
#[cfg(feature = "rrt_pathfinding")]
|
#[cfg(feature = "rrt_pathfinding")]
|
||||||
use rand::distributions::Uniform;
|
use rand::{
|
||||||
|
distributions::{Distribution, Uniform},
|
||||||
|
prelude::IteratorRandom,
|
||||||
|
};
|
||||||
use rand::{thread_rng, Rng};
|
use rand::{thread_rng, Rng};
|
||||||
#[cfg(feature = "rrt_pathfinding")]
|
#[cfg(feature = "rrt_pathfinding")]
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
@ -442,7 +445,7 @@ impl Chaser {
|
|||||||
self.last_search_tgt = Some(tgt);
|
self.last_search_tgt = Some(tgt);
|
||||||
|
|
||||||
// NOTE: Enable air paths when air braking has been figured out
|
// NOTE: Enable air paths when air braking has been figured out
|
||||||
let (path, complete) = /*if cfg!(rrt_pathfinding) && traversal_cfg.can_fly {
|
let (path, complete) = /*if cfg!(feature = "rrt_pathfinding") && traversal_cfg.can_fly {
|
||||||
find_air_path(vol, pos, tgt, &traversal_cfg)
|
find_air_path(vol, pos, tgt, &traversal_cfg)
|
||||||
} else */{
|
} else */{
|
||||||
find_path(&mut self.astar, vol, pos, tgt, &traversal_cfg)
|
find_path(&mut self.astar, vol, pos, tgt, &traversal_cfg)
|
||||||
@ -718,7 +721,6 @@ where
|
|||||||
V: BaseVol<Vox = Block> + ReadVol,
|
V: BaseVol<Vox = Block> + ReadVol,
|
||||||
{
|
{
|
||||||
let radius = traversal_cfg.node_tolerance;
|
let radius = traversal_cfg.node_tolerance;
|
||||||
let mut connect = false;
|
|
||||||
let total_dist_sqrd = startf.distance_squared(endf);
|
let total_dist_sqrd = startf.distance_squared(endf);
|
||||||
// First check if a straight line path works
|
// First check if a straight line path works
|
||||||
if vol
|
if vol
|
||||||
@ -731,7 +733,7 @@ where
|
|||||||
{
|
{
|
||||||
let mut path = Vec::new();
|
let mut path = Vec::new();
|
||||||
path.push(endf.map(|e| e.floor() as i32));
|
path.push(endf.map(|e| e.floor() as i32));
|
||||||
connect = true;
|
let connect = true;
|
||||||
(Some(path.into_iter().collect()), connect)
|
(Some(path.into_iter().collect()), connect)
|
||||||
// Else use RRTs
|
// Else use RRTs
|
||||||
} else {
|
} else {
|
||||||
@ -745,7 +747,7 @@ where
|
|||||||
//vol.get(*pos).ok().copied().unwrap_or_else(Block::empty).
|
//vol.get(*pos).ok().copied().unwrap_or_else(Block::empty).
|
||||||
// is_fluid();
|
// is_fluid();
|
||||||
};
|
};
|
||||||
informed_rrt_connect(start, end, is_traversable)
|
informed_rrt_connect(vol, startf, endf, is_traversable, radius)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -760,11 +762,17 @@ where
|
|||||||
/// with narrow gaps, such as navigating a maze.
|
/// with narrow gaps, such as navigating a maze.
|
||||||
/// Returns a path and whether that path is complete or not.
|
/// Returns a path and whether that path is complete or not.
|
||||||
#[cfg(feature = "rrt_pathfinding")]
|
#[cfg(feature = "rrt_pathfinding")]
|
||||||
fn informed_rrt_connect(
|
fn informed_rrt_connect<V>(
|
||||||
start: Vec3<f32>,
|
vol: &V,
|
||||||
end: Vec3<f32>,
|
startf: Vec3<f32>,
|
||||||
|
endf: Vec3<f32>,
|
||||||
is_valid_edge: impl Fn(&Vec3<f32>, &Vec3<f32>) -> bool,
|
is_valid_edge: impl Fn(&Vec3<f32>, &Vec3<f32>) -> bool,
|
||||||
) -> (Option<Path<Vec3<i32>>>, bool) {
|
radius: f32,
|
||||||
|
) -> (Option<Path<Vec3<i32>>>, bool)
|
||||||
|
where
|
||||||
|
V: BaseVol<Vox = Block> + ReadVol,
|
||||||
|
{
|
||||||
|
const MAX_POINTS: usize = 7000;
|
||||||
let mut path = Vec::new();
|
let mut path = Vec::new();
|
||||||
|
|
||||||
// Each tree has a vector of nodes
|
// Each tree has a vector of nodes
|
||||||
@ -784,20 +792,16 @@ fn informed_rrt_connect(
|
|||||||
let mut path2 = Vec::new();
|
let mut path2 = Vec::new();
|
||||||
|
|
||||||
// K-d trees are used to find the closest nodes rapidly
|
// K-d trees are used to find the closest nodes rapidly
|
||||||
let mut kdtree1 = KdTree::new();
|
let mut kdtree1: KdTree<f32, usize, 3, 32, u32> = KdTree::with_capacity(MAX_POINTS);
|
||||||
let mut kdtree2 = KdTree::new();
|
let mut kdtree2: KdTree<f32, usize, 3, 32, u32> = KdTree::with_capacity(MAX_POINTS);
|
||||||
|
|
||||||
// Add the start as the first node of the first k-d tree
|
// Add the start as the first node of the first k-d tree
|
||||||
kdtree1
|
kdtree1.add(&[startf.x, startf.y, startf.z], node_index1);
|
||||||
.add(&[startf.x, startf.y, startf.z], node_index1)
|
|
||||||
.unwrap_or_default();
|
|
||||||
nodes1.push(startf);
|
nodes1.push(startf);
|
||||||
node_index1 += 1;
|
node_index1 += 1;
|
||||||
|
|
||||||
// Add the end as the first node of the second k-d tree
|
// Add the end as the first node of the second k-d tree
|
||||||
kdtree2
|
kdtree2.add(&[endf.x, endf.y, endf.z], node_index2);
|
||||||
.add(&[endf.x, endf.y, endf.z], node_index2)
|
|
||||||
.unwrap_or_default();
|
|
||||||
nodes2.push(endf);
|
nodes2.push(endf);
|
||||||
node_index2 += 1;
|
node_index2 += 1;
|
||||||
|
|
||||||
@ -810,8 +814,8 @@ fn informed_rrt_connect(
|
|||||||
// sample spheroid volume. This increases in value until a path is found.
|
// sample spheroid volume. This increases in value until a path is found.
|
||||||
let mut search_parameter = 0.01;
|
let mut search_parameter = 0.01;
|
||||||
|
|
||||||
// Maximum of 7000 iterations
|
// Maximum of MAX_POINTS iterations
|
||||||
for _i in 0..7000 {
|
for _i in 0..MAX_POINTS {
|
||||||
if connect {
|
if connect {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -824,17 +828,19 @@ fn informed_rrt_connect(
|
|||||||
|
|
||||||
// Find the nearest nodes to the the sampled point
|
// Find the nearest nodes to the the sampled point
|
||||||
let nearest_index1 = kdtree1
|
let nearest_index1 = kdtree1
|
||||||
.nearest_one(
|
.nearest_one::<SquaredEuclidean>(&[
|
||||||
&[sampled_point1.x, sampled_point1.y, sampled_point1.z],
|
sampled_point1.x,
|
||||||
&squared_euclidean,
|
sampled_point1.y,
|
||||||
)
|
sampled_point1.z,
|
||||||
.map_or(0, |n| *n.1);
|
])
|
||||||
|
.item;
|
||||||
let nearest_index2 = kdtree2
|
let nearest_index2 = kdtree2
|
||||||
.nearest_one(
|
.nearest_one::<SquaredEuclidean>(&[
|
||||||
&[sampled_point2.x, sampled_point2.y, sampled_point2.z],
|
sampled_point2.x,
|
||||||
&squared_euclidean,
|
sampled_point2.y,
|
||||||
)
|
sampled_point2.z,
|
||||||
.map_or(0, |n| *n.1);
|
])
|
||||||
|
.item;
|
||||||
let nearest1 = nodes1[nearest_index1];
|
let nearest1 = nodes1[nearest_index1];
|
||||||
let nearest2 = nodes2[nearest_index2];
|
let nearest2 = nodes2[nearest_index2];
|
||||||
|
|
||||||
@ -844,49 +850,51 @@ fn informed_rrt_connect(
|
|||||||
|
|
||||||
// Ensure the new nodes are valid/traversable
|
// Ensure the new nodes are valid/traversable
|
||||||
if is_valid_edge(&nearest1, &new_point1) {
|
if is_valid_edge(&nearest1, &new_point1) {
|
||||||
kdtree1
|
kdtree1.add(&[new_point1.x, new_point1.y, new_point1.z], node_index1);
|
||||||
.add(&[new_point1.x, new_point1.y, new_point1.z], node_index1)
|
|
||||||
.unwrap_or_default();
|
|
||||||
nodes1.push(new_point1);
|
nodes1.push(new_point1);
|
||||||
parents1.insert(node_index1, nearest_index1);
|
parents1.insert(node_index1, nearest_index1);
|
||||||
node_index1 += 1;
|
node_index1 += 1;
|
||||||
// Check if the trees connect
|
// Check if the trees connect
|
||||||
if let Ok((check, index)) = kdtree2.nearest_one(
|
let NearestNeighbour {
|
||||||
&[new_point1.x, new_point1.y, new_point1.z],
|
distance: check,
|
||||||
&squared_euclidean,
|
item: index,
|
||||||
) {
|
} = kdtree2.nearest_one::<SquaredEuclidean>(&[
|
||||||
if check < radius {
|
new_point1.x,
|
||||||
let connection = nodes2[*index];
|
new_point1.y,
|
||||||
connection2_idx = *index;
|
new_point1.z,
|
||||||
nodes1.push(connection);
|
]);
|
||||||
connection1_idx = nodes1.len() - 1;
|
if check < radius {
|
||||||
parents1.insert(node_index1, node_index1 - 1);
|
let connection = nodes2[index];
|
||||||
connect = true;
|
connection2_idx = index;
|
||||||
}
|
nodes1.push(connection);
|
||||||
|
connection1_idx = nodes1.len() - 1;
|
||||||
|
parents1.insert(node_index1, node_index1 - 1);
|
||||||
|
connect = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Repeat the validity check for the second tree
|
// Repeat the validity check for the second tree
|
||||||
if is_valid_edge(&nearest2, &new_point2) {
|
if is_valid_edge(&nearest2, &new_point2) {
|
||||||
kdtree2
|
kdtree2.add(&[new_point2.x, new_point2.y, new_point1.z], node_index2);
|
||||||
.add(&[new_point2.x, new_point2.y, new_point1.z], node_index2)
|
|
||||||
.unwrap_or_default();
|
|
||||||
nodes2.push(new_point2);
|
nodes2.push(new_point2);
|
||||||
parents2.insert(node_index2, nearest_index2);
|
parents2.insert(node_index2, nearest_index2);
|
||||||
node_index2 += 1;
|
node_index2 += 1;
|
||||||
// Again check for a connection
|
// Again check for a connection
|
||||||
if let Ok((check, index)) = kdtree1.nearest_one(
|
let NearestNeighbour {
|
||||||
&[new_point2.x, new_point2.y, new_point1.z],
|
distance: check,
|
||||||
&squared_euclidean,
|
item: index,
|
||||||
) {
|
} = kdtree1.nearest_one::<SquaredEuclidean>(&[
|
||||||
if check < radius {
|
new_point2.x,
|
||||||
let connection = nodes1[*index];
|
new_point2.y,
|
||||||
connection1_idx = *index;
|
new_point1.z,
|
||||||
nodes2.push(connection);
|
]);
|
||||||
connection2_idx = nodes2.len() - 1;
|
if check < radius {
|
||||||
parents2.insert(node_index2, node_index2 - 1);
|
let connection = nodes1[index];
|
||||||
connect = true;
|
connection1_idx = index;
|
||||||
}
|
nodes2.push(connection);
|
||||||
|
connection2_idx = nodes2.len() - 1;
|
||||||
|
parents2.insert(node_index2, node_index2 - 1);
|
||||||
|
connect = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Increase the search parameter to widen the sample volume
|
// Increase the search parameter to widen the sample volume
|
||||||
@ -915,14 +923,14 @@ fn informed_rrt_connect(
|
|||||||
// If the trees did not connect, construct a path from the start to
|
// If the trees did not connect, construct a path from the start to
|
||||||
// the closest node to the end
|
// the closest node to the end
|
||||||
let mut current_node_index1 = kdtree1
|
let mut current_node_index1 = kdtree1
|
||||||
.nearest_one(&[endf.x, endf.y, endf.z], &squared_euclidean)
|
.nearest_one::<SquaredEuclidean>(&[endf.x, endf.y, endf.z])
|
||||||
.map_or(0, |c| *c.1);
|
.item;
|
||||||
// Attempt to pick a node other than the start node
|
// Attempt to pick a node other than the start node
|
||||||
for _i in 0..3 {
|
for _i in 0..3 {
|
||||||
if current_node_index1 == 0
|
if current_node_index1 == 0
|
||||||
|| nodes1[current_node_index1].distance_squared(startf) < 4.0
|
|| nodes1[current_node_index1].distance_squared(startf) < 4.0
|
||||||
{
|
{
|
||||||
if let Some(index) = parents1.values().choose(&mut thread_rng()) {
|
if let Some(index) = parents1.values().into_iter().choose(&mut thread_rng()) {
|
||||||
current_node_index1 = *index;
|
current_node_index1 = *index;
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
@ -973,6 +981,7 @@ fn informed_rrt_connect(
|
|||||||
node = path[node_idx];
|
node = path[node_idx];
|
||||||
}
|
}
|
||||||
path = new_path;
|
path = new_path;
|
||||||
|
(Some(path.into_iter().collect()), connect)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a random point within a radially symmetrical ellipsoid with given
|
/// Returns a random point within a radially symmetrical ellipsoid with given
|
||||||
|
@ -49,7 +49,8 @@ rayon = { workspace = true }
|
|||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
ron = { workspace = true }
|
ron = { workspace = true }
|
||||||
# inline_tweak = { workspace = true, features = ["derive"] }
|
# inline_tweak = { workspace = true, features = ["derive"] }
|
||||||
kiddo = "0.2"
|
kiddo = "4.2.0"
|
||||||
|
fixed = "1"
|
||||||
strum = { workspace = true }
|
strum = { workspace = true }
|
||||||
|
|
||||||
# compression benchmarks
|
# compression benchmarks
|
||||||
|
@ -493,7 +493,8 @@ impl VoxelImageEncoding for MixedEncodingDenseSprites {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use kiddo::KdTree;
|
use fixed::types::U32F0;
|
||||||
|
use kiddo::fixed::{distance::SquaredEuclidean, kdtree::KdTree};
|
||||||
use rstar::{PointDistance, RTree, RTreeObject, RTreeParams};
|
use rstar::{PointDistance, RTree, RTreeObject, RTreeParams};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -548,17 +549,16 @@ lazy_static::lazy_static! {
|
|||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
};
|
};
|
||||||
pub static ref PALETTE_KDTREE: HashMap<BlockKind, KdTree<f32, u8, 3>> = {
|
pub static ref PALETTE_KDTREE: HashMap<BlockKind, KdTree<U32F0, u16, 3, 32, u32>> = {
|
||||||
let ron_bytes = include_bytes!("palettes.ron");
|
let ron_bytes = include_bytes!("palettes.ron");
|
||||||
let palettes: HashMap<BlockKind, Vec<Rgb<u8>>> =
|
let palettes: HashMap<BlockKind, Vec<Rgb<u8>>> =
|
||||||
ron::de::from_bytes(ron_bytes).expect("palette should parse");
|
ron::de::from_bytes(ron_bytes).expect("palette should parse");
|
||||||
palettes
|
palettes
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(k, v)| {
|
.map(|(k, v)| {
|
||||||
let mut tree = KdTree::new();
|
let mut tree: KdTree<U32F0, u16, 3, 32, u32> = KdTree::new();
|
||||||
for (i, rgb) in v.into_iter().enumerate() {
|
for (i, rgb) in v.into_iter().enumerate() {
|
||||||
tree.add(&[rgb.r as f32, rgb.g as f32, rgb.b as f32], i as u8)
|
tree.add(&[U32F0::from(rgb.r), U32F0::from(rgb.g), U32F0::from(rgb.b)], i as u16);
|
||||||
.expect("kdtree insert should succeed");
|
|
||||||
}
|
}
|
||||||
(k, tree)
|
(k, tree)
|
||||||
})
|
})
|
||||||
@ -570,14 +570,18 @@ pub trait NearestNeighbor {
|
|||||||
fn nearest_neighbor(&self, x: &Rgb<u8>) -> Option<u8>;
|
fn nearest_neighbor(&self, x: &Rgb<u8>) -> Option<u8>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NearestNeighbor for KdTree<f32, u8, 3> {
|
impl NearestNeighbor for KdTree<U32F0, u16, 3, 32, u32> {
|
||||||
fn nearest_neighbor(&self, x: &Rgb<u8>) -> Option<u8> {
|
fn nearest_neighbor(&self, x: &Rgb<u8>) -> Option<u8> {
|
||||||
self.nearest_one(
|
Some(
|
||||||
&[x.r as f32, x.g as f32, x.b as f32],
|
self.nearest_one::<SquaredEuclidean>(&[
|
||||||
&kiddo::distance::squared_euclidean,
|
U32F0::from(x.r),
|
||||||
|
U32F0::from(x.g),
|
||||||
|
U32F0::from(x.b),
|
||||||
|
])
|
||||||
|
.item
|
||||||
|
.try_into()
|
||||||
|
.unwrap(),
|
||||||
)
|
)
|
||||||
.map(|(_, i)| *i)
|
|
||||||
.ok()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,17 +4,28 @@ use common::{
|
|||||||
vol::{IntoVolIterator, RectVolSize},
|
vol::{IntoVolIterator, RectVolSize},
|
||||||
};
|
};
|
||||||
use fallible_iterator::FallibleIterator;
|
use fallible_iterator::FallibleIterator;
|
||||||
use kiddo::{distance::squared_euclidean, KdTree};
|
use fixed::{
|
||||||
|
types::{extra::U0, U32F0, U8F0},
|
||||||
|
FixedU8,
|
||||||
|
};
|
||||||
|
use kiddo::{
|
||||||
|
fixed::{distance::SquaredEuclidean, kdtree::KdTree},
|
||||||
|
nearest_neighbour::NearestNeighbour,
|
||||||
|
};
|
||||||
|
use num_traits::identities::{One, Zero};
|
||||||
use rayon::{
|
use rayon::{
|
||||||
iter::{IntoParallelIterator, ParallelIterator},
|
iter::{IntoParallelIterator, ParallelIterator},
|
||||||
ThreadPoolBuilder,
|
ThreadPoolBuilder,
|
||||||
};
|
};
|
||||||
use rusqlite::{Connection, ToSql, Transaction, TransactionBehavior};
|
use rusqlite::{Connection, ToSql, Transaction, TransactionBehavior};
|
||||||
|
//use serde::{Serialize, Deserialize};
|
||||||
use std::{
|
use std::{
|
||||||
|
cmp::Ordering,
|
||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet},
|
||||||
error::Error,
|
error::Error,
|
||||||
fs::File,
|
fs::File,
|
||||||
io::Write,
|
io::Write,
|
||||||
|
ops::{Add, Mul, SubAssign},
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
sync::mpsc,
|
sync::mpsc,
|
||||||
time::{SystemTime, UNIX_EPOCH},
|
time::{SystemTime, UNIX_EPOCH},
|
||||||
@ -25,6 +36,75 @@ use veloren_world::{
|
|||||||
World,
|
World,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Clone, Copy, Hash, Eq, PartialEq /* , Serialize, Deserialize */)]
|
||||||
|
struct KiddoRgb(Rgb<U8F0>);
|
||||||
|
|
||||||
|
impl PartialOrd for KiddoRgb {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for KiddoRgb {
|
||||||
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
|
(self.0.r, self.0.g, self.0.b).cmp(&(other.0.r, other.0.g, other.0.b))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Zero for KiddoRgb {
|
||||||
|
fn zero() -> Self { KiddoRgb(Rgb::zero()) }
|
||||||
|
|
||||||
|
fn is_zero(&self) -> bool { self == &Self::zero() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl One for KiddoRgb {
|
||||||
|
fn one() -> Self { KiddoRgb(Rgb::one()) }
|
||||||
|
|
||||||
|
fn is_one(&self) -> bool { self == &Self::one() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SubAssign for KiddoRgb {
|
||||||
|
fn sub_assign(&mut self, other: Self) {
|
||||||
|
*self = Self(Rgb {
|
||||||
|
r: self.0.r - other.0.r,
|
||||||
|
g: self.0.g - other.0.g,
|
||||||
|
b: self.0.b - other.0.b,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add for KiddoRgb {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn add(self, other: Self) -> Self {
|
||||||
|
Self(Rgb {
|
||||||
|
r: self.0.r + other.0.r,
|
||||||
|
g: self.0.g + other.0.g,
|
||||||
|
b: self.0.b + other.0.b,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul for KiddoRgb {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn mul(self, rhs: Self) -> Self {
|
||||||
|
Self(Rgb {
|
||||||
|
r: self.0.r * rhs.0.r,
|
||||||
|
g: self.0.g * rhs.0.g,
|
||||||
|
b: self.0.b * rhs.0.b,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Rgb<u8>> for KiddoRgb {
|
||||||
|
fn from(value: Rgb<u8>) -> Self {
|
||||||
|
Self(Rgb {
|
||||||
|
r: FixedU8::<U0>::from_num(value.r),
|
||||||
|
g: FixedU8::<U0>::from_num(value.g),
|
||||||
|
b: FixedU8::<U0>::from_num(value.b),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn block_statistics_db(db_path: &str) -> Result<Connection, Box<dyn Error>> {
|
fn block_statistics_db(db_path: &str) -> Result<Connection, Box<dyn Error>> {
|
||||||
let conn = Connection::open(db_path)?;
|
let conn = Connection::open(db_path)?;
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
@ -95,31 +175,40 @@ fn generate(db_path: &str, ymin: Option<i32>, ymax: Option<i32>) -> Result<(), B
|
|||||||
if existing_chunks.contains(&(x, y)) {
|
if existing_chunks.contains(&(x, y)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
println!("Generating chunk at ({}, {})", x, y);
|
|
||||||
let start_time = SystemTime::now();
|
let start_time = SystemTime::now();
|
||||||
if let Ok((chunk, _supplement)) =
|
if let Ok((chunk, _supplement)) =
|
||||||
world.generate_chunk(index.as_index_ref(), Vec2::new(x, y), None, || false, None)
|
world.generate_chunk(index.as_index_ref(), Vec2::new(x, y), None, || false, None)
|
||||||
{
|
{
|
||||||
let end_time = SystemTime::now();
|
let end_time = SystemTime::now();
|
||||||
// TODO: can kiddo be made to work without the `Float` bound, so we can use
|
// TODO: The KiddoRgb wrapper type is necessary to satisfy trait bounds.
|
||||||
// `KdTree<u8, (), 3>` (currently it uses 15 bytes per point instead of 3)?
|
// We store the colors twice currently, once as coordinates and another time
|
||||||
let mut block_colors = KdTree::<f32, Rgb<u8>, 3>::new();
|
// as Content. Kiddo version 5.x is supposed to add the ability to have
|
||||||
|
// Content be (), which would be useful here. Once that's added, do that.
|
||||||
|
// TODO: dist_sq is the same type as the coordinates, and since squared
|
||||||
|
// euclidean distances between colors go way higher than 255,
|
||||||
|
// we're using a U32F0 here instead of the optimal U8F0 (A U16F0
|
||||||
|
// works too, but it could theoretically still overflow so U32F0
|
||||||
|
// is used to be safe). If this ever changes, replace U32F0 with
|
||||||
|
// U8F0.
|
||||||
|
let mut block_colors: KdTree<U32F0, KiddoRgb, 3, 32, u32> = KdTree::new();
|
||||||
let mut block_counts = HashMap::new();
|
let mut block_counts = HashMap::new();
|
||||||
let mut sprite_counts = HashMap::new();
|
let mut sprite_counts = HashMap::new();
|
||||||
let lo = Vec3::new(0, 0, chunk.get_min_z());
|
let lo = Vec3::new(0, 0, chunk.get_min_z());
|
||||||
let hi = TerrainChunkSize::RECT_SIZE.as_().with_z(chunk.get_max_z());
|
let hi = TerrainChunkSize::RECT_SIZE.as_().with_z(chunk.get_max_z());
|
||||||
let height = chunk.get_max_z() - chunk.get_min_z();
|
let height = chunk.get_max_z() - chunk.get_min_z();
|
||||||
for (_, block) in chunk.vol_iter(lo, hi) {
|
for (_, block) in chunk.vol_iter(lo, hi) {
|
||||||
let mut rgb = block.get_color().unwrap_or_else(|| Rgb::new(0, 0, 0));
|
let mut rgb =
|
||||||
let color: [f32; 3] = [rgb.r as _, rgb.g as _, rgb.b as _];
|
KiddoRgb::from(block.get_color().unwrap_or_else(|| Rgb::new(0, 0, 0)));
|
||||||
if let Ok((dist, nearest)) =
|
let color: [U32F0; 3] = [rgb.0.r.into(), rgb.0.g.into(), rgb.0.b.into()];
|
||||||
block_colors.nearest_one(&color, &squared_euclidean)
|
let NearestNeighbour {
|
||||||
{
|
distance: dist_sq,
|
||||||
if dist < (5.0f32).powf(2.0) {
|
item: nearest,
|
||||||
rgb = *nearest;
|
} = block_colors.nearest_one::<SquaredEuclidean>(&color);
|
||||||
}
|
if dist_sq < 5_u32.pow(2) {
|
||||||
|
rgb = nearest;
|
||||||
|
} else {
|
||||||
|
block_colors.add(&color, rgb);
|
||||||
}
|
}
|
||||||
let _ = block_colors.add(&color, rgb);
|
|
||||||
*block_counts.entry((block.kind(), rgb)).or_insert(0) += 1;
|
*block_counts.entry((block.kind(), rgb)).or_insert(0) += 1;
|
||||||
if let Some(sprite) = block.get_sprite() {
|
if let Some(sprite) = block.get_sprite() {
|
||||||
*sprite_counts.entry(sprite).or_insert(0) += 1;
|
*sprite_counts.entry(sprite).or_insert(0) += 1;
|
||||||
@ -139,6 +228,7 @@ fn generate(db_path: &str, ymin: Option<i32>, ymax: Option<i32>) -> Result<(), B
|
|||||||
});
|
});
|
||||||
let mut tx = Transaction::new_unchecked(&conn, TransactionBehavior::Deferred)?;
|
let mut tx = Transaction::new_unchecked(&conn, TransactionBehavior::Deferred)?;
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
|
let mut j = 0;
|
||||||
while let Ok((x, y, height, start_time, end_time, block_counts, sprite_counts)) = rx.recv() {
|
while let Ok((x, y, height, start_time, end_time, block_counts, sprite_counts)) = rx.recv() {
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
let mut insert_block = tx.prepare_cached("
|
let mut insert_block = tx.prepare_cached("
|
||||||
@ -155,15 +245,14 @@ fn generate(db_path: &str, ymin: Option<i32>, ymax: Option<i32>) -> Result<(), B
|
|||||||
REPLACE INTO chunk (xcoord, ycoord, height, start_time, end_time)
|
REPLACE INTO chunk (xcoord, ycoord, height, start_time, end_time)
|
||||||
VALUES (?1, ?2, ?3, ?4, ?5)
|
VALUES (?1, ?2, ?3, ?4, ?5)
|
||||||
")?;
|
")?;
|
||||||
println!("Inserting results for chunk at ({}, {}): {}", x, y, i);
|
|
||||||
for ((kind, color), count) in block_counts.iter() {
|
for ((kind, color), count) in block_counts.iter() {
|
||||||
insert_block.execute([
|
insert_block.execute([
|
||||||
&x as &dyn ToSql,
|
&x as &dyn ToSql,
|
||||||
&y,
|
&y,
|
||||||
&format!("{:?}", kind),
|
&format!("{:?}", kind),
|
||||||
&color.r,
|
&color.0.r.to_num::<u8>(),
|
||||||
&color.g,
|
&color.0.g.to_num::<u8>(),
|
||||||
&color.b,
|
&color.0.b.to_num::<u8>(),
|
||||||
&count,
|
&count,
|
||||||
])?;
|
])?;
|
||||||
}
|
}
|
||||||
@ -174,12 +263,13 @@ fn generate(db_path: &str, ymin: Option<i32>, ymax: Option<i32>) -> Result<(), B
|
|||||||
let end_time = end_time.duration_since(UNIX_EPOCH)?.as_secs_f64();
|
let end_time = end_time.duration_since(UNIX_EPOCH)?.as_secs_f64();
|
||||||
insert_chunk.execute([&x as &dyn ToSql, &y, &height, &start_time, &end_time])?;
|
insert_chunk.execute([&x as &dyn ToSql, &y, &height, &start_time, &end_time])?;
|
||||||
if i % 32 == 0 {
|
if i % 32 == 0 {
|
||||||
println!("Committing last 32 chunks");
|
println!("Committing hunk of 32 chunks: {}", j);
|
||||||
drop(insert_block);
|
drop(insert_block);
|
||||||
drop(insert_sprite);
|
drop(insert_sprite);
|
||||||
drop(insert_chunk);
|
drop(insert_chunk);
|
||||||
tx.commit()?;
|
tx.commit()?;
|
||||||
tx = Transaction::new_unchecked(&conn, TransactionBehavior::Deferred)?;
|
tx = Transaction::new_unchecked(&conn, TransactionBehavior::Deferred)?;
|
||||||
|
j += 1;
|
||||||
}
|
}
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
@ -189,12 +279,12 @@ fn generate(db_path: &str, ymin: Option<i32>, ymax: Option<i32>) -> Result<(), B
|
|||||||
fn palette(conn: Connection) -> Result<(), Box<dyn Error>> {
|
fn palette(conn: Connection) -> Result<(), Box<dyn Error>> {
|
||||||
let mut stmt =
|
let mut stmt =
|
||||||
conn.prepare("SELECT kind, r, g, b, SUM(quantity) FROM block GROUP BY kind, r, g, b")?;
|
conn.prepare("SELECT kind, r, g, b, SUM(quantity) FROM block GROUP BY kind, r, g, b")?;
|
||||||
let mut block_colors: HashMap<BlockKind, Vec<(Rgb<u8>, i64)>> = HashMap::new();
|
let mut block_colors: HashMap<BlockKind, Vec<(KiddoRgb, i64)>> = HashMap::new();
|
||||||
|
|
||||||
let mut rows = stmt.query([])?;
|
let mut rows = stmt.query([])?;
|
||||||
while let Some(row) = rows.next()? {
|
while let Some(row) = rows.next()? {
|
||||||
let kind = BlockKind::from_str(&row.get::<_, String>(0)?)?;
|
let kind = BlockKind::from_str(&row.get::<_, String>(0)?)?;
|
||||||
let rgb: Rgb<u8> = Rgb::new(row.get(1)?, row.get(2)?, row.get(3)?);
|
let rgb: KiddoRgb = KiddoRgb::from(Rgb::new(row.get(1)?, row.get(2)?, row.get(3)?));
|
||||||
let count: i64 = row.get(4)?;
|
let count: i64 = row.get(4)?;
|
||||||
block_colors.entry(kind).or_default().push((rgb, count));
|
block_colors.entry(kind).or_default().push((rgb, count));
|
||||||
}
|
}
|
||||||
@ -202,7 +292,7 @@ fn palette(conn: Connection) -> Result<(), Box<dyn Error>> {
|
|||||||
v.sort_by(|a, b| b.1.cmp(&a.1));
|
v.sort_by(|a, b| b.1.cmp(&a.1));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut palettes: HashMap<BlockKind, Vec<Rgb<u8>>> = HashMap::new();
|
let mut palettes: HashMap<BlockKind, Vec<KiddoRgb>> = HashMap::new();
|
||||||
for (kind, colors) in block_colors.iter() {
|
for (kind, colors) in block_colors.iter() {
|
||||||
let palette = palettes.entry(*kind).or_default();
|
let palette = palettes.entry(*kind).or_default();
|
||||||
if colors.len() <= 256 {
|
if colors.len() <= 256 {
|
||||||
@ -213,24 +303,43 @@ fn palette(conn: Connection) -> Result<(), Box<dyn Error>> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let mut radius = 1024.0;
|
let mut radius = 1024.0;
|
||||||
let mut tree = KdTree::<f32, Rgb<u8>, 3>::new();
|
let mut tree: KdTree<U32F0, KiddoRgb, 3, 256, u32> = KdTree::new();
|
||||||
while palette.len() < 256 {
|
while palette.len() < 256 {
|
||||||
if let Some((color, _)) = colors.iter().find(|(color, _)| {
|
if let Some((color, _)) = colors.iter().find(|(color, _)| {
|
||||||
tree.nearest_one(
|
tree.nearest_one::<SquaredEuclidean>(&[
|
||||||
&[color.r as f32, color.g as f32, color.b as f32],
|
color.0.r.into(),
|
||||||
&squared_euclidean,
|
color.0.g.into(),
|
||||||
)
|
color.0.b.into(),
|
||||||
.map(|(dist, _)| dist > radius)
|
])
|
||||||
.unwrap_or(true)
|
.distance
|
||||||
|
> radius
|
||||||
}) {
|
}) {
|
||||||
palette.push(*color);
|
palette.push(*color);
|
||||||
tree.add(&[color.r as f32, color.g as f32, color.b as f32], *color)?;
|
tree.add(
|
||||||
|
&[color.0.r.into(), color.0.g.into(), color.0.b.into()],
|
||||||
|
*color,
|
||||||
|
);
|
||||||
println!("{:?}, {:?}: {:?}", kind, radius, *color);
|
println!("{:?}, {:?}: {:?}", kind, radius, *color);
|
||||||
} else {
|
} else {
|
||||||
radius -= 1.0;
|
radius -= 1.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let palettes: HashMap<BlockKind, Vec<Rgb<u8>>> = palettes
|
||||||
|
.iter()
|
||||||
|
.map(|(k, v)| {
|
||||||
|
(
|
||||||
|
*k,
|
||||||
|
v.iter()
|
||||||
|
.map(|c| Rgb {
|
||||||
|
r: c.0.r.to_num::<u8>(),
|
||||||
|
g: c.0.g.to_num::<u8>(),
|
||||||
|
b: c.0.b.to_num::<u8>(),
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
let mut f = File::create("palettes.ron")?;
|
let mut f = File::create("palettes.ron")?;
|
||||||
let pretty = ron::ser::PrettyConfig::default().depth_limit(2);
|
let pretty = ron::ser::PrettyConfig::default().depth_limit(2);
|
||||||
write!(f, "{}", ron::ser::to_string_pretty(&palettes, pretty)?)?;
|
write!(f, "{}", ron::ser::to_string_pretty(&palettes, pretty)?)?;
|
||||||
|
@ -9,7 +9,7 @@ use common::{
|
|||||||
generation::{ChunkSupplement, EntityInfo},
|
generation::{ChunkSupplement, EntityInfo},
|
||||||
terrain::{Structure as PrefabStructure, StructuresGroup},
|
terrain::{Structure as PrefabStructure, StructuresGroup},
|
||||||
};
|
};
|
||||||
use kiddo::{distance::squared_euclidean, KdTree};
|
use kiddo::{float::kdtree::KdTree, SquaredEuclidean};
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
@ -1974,13 +1974,14 @@ impl Tunnels {
|
|||||||
where
|
where
|
||||||
F: Fn(Vec3<i32>, Vec3<i32>) -> bool,
|
F: Fn(Vec3<i32>, Vec3<i32>) -> bool,
|
||||||
{
|
{
|
||||||
|
const MAX_POINTS: usize = 7000;
|
||||||
let mut nodes = Vec::new();
|
let mut nodes = Vec::new();
|
||||||
let mut node_index: usize = 0;
|
let mut node_index: usize = 0;
|
||||||
|
|
||||||
// HashMap<ChildNode, ParentNode>
|
// HashMap<ChildNode, ParentNode>
|
||||||
let mut parents = HashMap::new();
|
let mut parents = HashMap::new();
|
||||||
|
|
||||||
let mut kdtree = KdTree::new();
|
let mut kdtree: KdTree<f32, usize, 3, 32, u32> = KdTree::with_capacity(MAX_POINTS);
|
||||||
let startf = start.map(|a| (a + 1) as f32);
|
let startf = start.map(|a| (a + 1) as f32);
|
||||||
let endf = end.map(|a| (a + 1) as f32);
|
let endf = end.map(|a| (a + 1) as f32);
|
||||||
|
|
||||||
@ -1995,14 +1996,12 @@ impl Tunnels {
|
|||||||
startf.z.max(endf.z),
|
startf.z.max(endf.z),
|
||||||
);
|
);
|
||||||
|
|
||||||
kdtree
|
kdtree.add(&[startf.x, startf.y, startf.z], node_index);
|
||||||
.add(&[startf.x, startf.y, startf.z], node_index)
|
|
||||||
.ok()?;
|
|
||||||
nodes.push(startf);
|
nodes.push(startf);
|
||||||
node_index += 1;
|
node_index += 1;
|
||||||
let mut connect = false;
|
let mut connect = false;
|
||||||
|
|
||||||
for _i in 0..7000 {
|
for _i in 0..MAX_POINTS {
|
||||||
let radius: f32 = rng.gen_range(radius_range.0..radius_range.1);
|
let radius: f32 = rng.gen_range(radius_range.0..radius_range.1);
|
||||||
let radius_sqrd = radius.powi(2);
|
let radius_sqrd = radius.powi(2);
|
||||||
if connect {
|
if connect {
|
||||||
@ -2013,13 +2012,13 @@ impl Tunnels {
|
|||||||
rng.gen_range(min.y - 20.0..max.y + 20.0),
|
rng.gen_range(min.y - 20.0..max.y + 20.0),
|
||||||
rng.gen_range(min.z - 20.0..max.z - 7.0),
|
rng.gen_range(min.z - 20.0..max.z - 7.0),
|
||||||
);
|
);
|
||||||
let nearest_index = *kdtree
|
let nearest_index = kdtree
|
||||||
.nearest_one(
|
.nearest_one::<SquaredEuclidean>(&[
|
||||||
&[sampled_point.x, sampled_point.y, sampled_point.z],
|
sampled_point.x,
|
||||||
&squared_euclidean,
|
sampled_point.y,
|
||||||
)
|
sampled_point.z,
|
||||||
.ok()?
|
])
|
||||||
.1;
|
.item;
|
||||||
let nearest = nodes[nearest_index];
|
let nearest = nodes[nearest_index];
|
||||||
let dist_sqrd = sampled_point.distance_squared(nearest);
|
let dist_sqrd = sampled_point.distance_squared(nearest);
|
||||||
let new_point = if dist_sqrd > radius_sqrd {
|
let new_point = if dist_sqrd > radius_sqrd {
|
||||||
@ -2031,24 +2030,21 @@ impl Tunnels {
|
|||||||
nearest.map(|e| e.floor() as i32),
|
nearest.map(|e| e.floor() as i32),
|
||||||
new_point.map(|e| e.floor() as i32),
|
new_point.map(|e| e.floor() as i32),
|
||||||
) {
|
) {
|
||||||
kdtree
|
kdtree.add(&[new_point.x, new_point.y, new_point.z], node_index);
|
||||||
.add(&[new_point.x, new_point.y, new_point.z], node_index)
|
|
||||||
.ok()?;
|
|
||||||
nodes.push(new_point);
|
nodes.push(new_point);
|
||||||
parents.insert(node_index, nearest_index);
|
parents.insert(node_index, nearest_index);
|
||||||
node_index += 1;
|
node_index += 1;
|
||||||
}
|
}
|
||||||
if new_point.distance_squared(endf) < radius.powi(2) {
|
if new_point.distance_squared(endf) < radius_sqrd {
|
||||||
connect = true;
|
connect = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut path = Vec::new();
|
let mut path = Vec::new();
|
||||||
let nearest_index = *kdtree
|
let nearest_index = kdtree
|
||||||
.nearest_one(&[endf.x, endf.y, endf.z], &squared_euclidean)
|
.nearest_one::<SquaredEuclidean>(&[endf.x, endf.y, endf.z])
|
||||||
.ok()?
|
.item;
|
||||||
.1;
|
kdtree.add(&[endf.x, endf.y, endf.z], node_index);
|
||||||
kdtree.add(&[endf.x, endf.y, endf.z], node_index).ok()?;
|
|
||||||
nodes.push(endf);
|
nodes.push(endf);
|
||||||
parents.insert(node_index, nearest_index);
|
parents.insert(node_index, nearest_index);
|
||||||
path.push(endf);
|
path.push(endf);
|
||||||
|
Loading…
Reference in New Issue
Block a user