From b7401bef1b4e475d1bf69f559878066d435707bb Mon Sep 17 00:00:00 2001 From: jeangab Date: Tue, 8 Aug 2023 14:07:58 -0400 Subject: [PATCH 01/11] wip: refactor space colonization to use mutables instead of refCell --- src/components/background.rs | 13 +- src/space_colonization/mod.rs | 6 +- src/space_colonization/space_colonization.rs | 132 ++++++++++--------- 3 files changed, 82 insertions(+), 69 deletions(-) diff --git a/src/components/background.rs b/src/components/background.rs index 28b0fea..fb56834 100644 --- a/src/components/background.rs +++ b/src/components/background.rs @@ -18,7 +18,7 @@ pub fn Background(cx: Scope, class: &'static str) -> impl IntoView { let height = canvas_parent.client_height(); canvas.set_width(u32::try_from(width).unwrap()); canvas.set_height(u32::try_from(height).unwrap()); - let sc = SpaceColonization::new(width.try_into().unwrap(), height.try_into().unwrap()); + let mut sc = SpaceColonization::new(width.try_into().unwrap(), height.try_into().unwrap()); // TODO Resize on window resize log!( "TODO resize on window resize canvas parent size = {} {}", @@ -38,10 +38,6 @@ pub fn Background(cx: Scope, class: &'static str) -> impl IntoView { context.set_fill_style(&JsValue::from("yellow")); log!("About to render nodes"); let start_time = window().unwrap().performance().unwrap().now(); - for n in sc.nodes_tree.borrow().iter() { - context.fill_rect(n.position.x.into(), n.position.y.into(), 5.0, 5.0); - } - context.begin_path(); let render_node_fn = |n: &Node, child: &Node| { context.move_to(n.position.x.into(), n.position.y.into()); @@ -52,14 +48,13 @@ pub fn Background(cx: Scope, class: &'static str) -> impl IntoView { context.stroke(); context.set_fill_style(&JsValue::from("magenta")); - for a in sc.attractors.borrow().iter() { + for a in sc.attractors.iter() { context.fill_rect(a.position.x.into(), a.position.y.into(), 5.0, 5.0); } let end_time = window().unwrap().performance().unwrap().now(); log!( - "Rendering {} nodes and {} attractors took {}", - sc.nodes_tree.borrow().len(), - sc.attractors.borrow().len(), + "Rendering nodes and {} attractors took {}", + sc.attractors.len(), end_time - start_time ); diff --git a/src/space_colonization/mod.rs b/src/space_colonization/mod.rs index 1447000..b84f929 100644 --- a/src/space_colonization/mod.rs +++ b/src/space_colonization/mod.rs @@ -12,7 +12,7 @@ extern "C" { fn performance() -> web_sys::Performance; } -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq, Hash)] pub struct Attractor { pub position: Point, pub dead: bool, @@ -38,6 +38,9 @@ impl Attractor { /// - Probably worth marking nodes as dead when no attractor is in range #[derive(Debug, PartialEq, Eq)] pub struct Node { + /// When a Node is born it is growing + /// it stops growing when there is no attractor in range + pub growing: bool, pub position: Point, pub children: Vec, } @@ -76,6 +79,7 @@ impl Node { fn new(position: Point) -> Self { Self { position, + growing: true, children: Vec::new().into(), } } diff --git a/src/space_colonization/space_colonization.rs b/src/space_colonization/space_colonization.rs index bb0babc..718850f 100644 --- a/src/space_colonization/space_colonization.rs +++ b/src/space_colonization/space_colonization.rs @@ -1,5 +1,4 @@ -use super::math::calculate_new_node_position; -use super::{Attractor, Node, NodeRef, Point}; +use super::{Attractor, Node, Point}; use log::info; use rand::thread_rng; use rand::Rng; @@ -40,9 +39,21 @@ pub struct SpaceColonization { /// /// If density is 10, then there will be an average distance of 10 between attractors density: i32, - new_nodes: Vec<(NodeRef, Node)>, - /// Flat list of all nodes in the tree - /// [node, child1, grand-child, child2, grand-child2] + /// Tree of all nodes in the space. There can be multiple root nodes. + /// ```yaml + /// [ + /// node: { + /// position: (x,y), + /// children : [ + /// child1 : { + /// position, children: [ grand-child1, grand-child2 ] + /// }, + /// child2 : {...} + /// ], + /// }, + /// node2: { ...another tree }, + /// ] + /// ``` nodes: Vec, pub attractors: Vec, } @@ -50,10 +61,7 @@ pub struct SpaceColonization { impl SpaceColonization { pub fn new(width: i32, height: i32) -> SpaceColonization { let mut nodes_vec = Vec::new(); - nodes_vec.push(Node { - position: Point { x: 100, y: 100 }, - children: Vec::new(), - }); + nodes_vec.push(Node::new(Point::new((100, 100)))); let attractors = Vec::new(); let mut sc = SpaceColonization { @@ -67,7 +75,6 @@ impl SpaceColonization { density: 30, nodes: nodes_vec, attractors, - new_nodes: Vec::new(), }; sc.place_attractors(); @@ -93,7 +100,6 @@ impl SpaceColonization { density: 3, nodes, attractors, - new_nodes: Vec::new(), } } @@ -147,78 +153,87 @@ impl SpaceColonization { } } - pub fn grow(&self) { + pub fn grow(&mut self) { // TODO - // Find a clean API that will be stable across refactoring - // Write the test against this api including performance - // Find a way to make a compile-time safe datastructure that will ensure that + // [x] Find a clean API that will be stable across refactoring + // [ ] Write the test against this api including performance + // [x] Find a way to make a compile-time safe datastructure that will ensure that // - I can store my attractors and their state (remove them or update them when dead) // - I can store my nodes and their state // - I can efficiently render my nodes on a canvas // - I use as little memory as possible // - I can update my nodes self.grow_nodes(); - println!("new nodes for iteration {:?}", self.new_nodes); - let mut nodes_mut = self.nodes; - for new_pair in self.new_nodes.iter() { - new_pair.0.children.push(new_pair.1); - nodes_mut.push(new_pair.1); - } - self.new_nodes.clear(); } - pub fn grow_nodes(&self) { + pub fn grow_nodes(&mut self) { // iterate through attractors // find closest node within attraction range // build a map of nodes to affecting attractors // attractors within the attraction range that this node is the closest to // // calculate new node position - let attractors = self.attractors; - let mut growing_paths: HashMap<, Vec> = HashMap::new(); - for a in attractors.iter() { - if a.dead { - continue; - } - let mut closest_node: Option = None; - let mut closest_node_distance = f64::MAX; - - for n in self.nodes.iter() { - let distance = n.position.distance(&a.position); - if distance <= self.attraction_distance as f64 { - // TODO make sure it is closest node amongs all nodes - if distance < closest_node_distance { - closest_node = Some(n); - closest_node_distance = distance; - if distance < self.kill_distance as f64 { - a.dead.replace(true); - } - } - } - } - if let Some(node) = closest_node { - if let Some(attractors) = growing_paths.get_mut(&node) { - attractors.push(a); - } else { - let mut attractors = Vec::new(); - attractors.push(a); - growing_paths.insert(node, attractors); - } - } - } + let mut growing_paths: HashMap<*mut Node, Vec<&Attractor>> = HashMap::new(); + let mut influence_map = self.get_closest_node_for_attractors(); + /* for growth_cell in growing_paths { let position = calculate_new_node_position(&growth_cell, self.segment_length); for a in growth_cell.1 { if position.distance(&a.position) < self.kill_distance as f64 { - a.dead.replace(true); + a.dead = true; + } + } + } + */ + } + + fn get_closest_node_for_attractors(&self) -> HashMap<&Attractor, (&Node, f64)> { + let mut map = HashMap::new(); + self.build_attractor_map(&self.nodes, map); + + + + map + } + + // TODO use a struct instead of (&Node, f64) tuple + fn build_attractor_map<'a>(self, nodes: &'a Vec, mut map: HashMap<&'a Attractor, (&'a Node, f64)>) { + for n in nodes.iter() { + if !n.growing { + continue; + } + // TODO figure out that borrowing mess + let attractors: Vec<(&Attractor, f64)> = self.find_attractors_in_range(n); + if attractors.is_empty() { + n.growing = false; + continue; + } + + for a in attractors { + if let Some(closest) = map.get(a.0) { + if a.1 < closest.1 { + map.insert(a.0, (n, a.1)); + } + } else { + map.insert(a.0, (n, a.1)); } } - self.new_nodes - .push((growth_cell.0, Node::new(position))); } } + + fn find_attractors_in_range(&self, n: &Node) -> Vec<(&Attractor, f64)> { + let mut attractors_in_range = Vec::new(); + for a in self.attractors.iter() { + let distance = n.position.distance(&a.position); + if distance < self.attraction_distance as f64 { + attractors_in_range.push((a, distance)); + } + } + attractors_in_range + } } + #[cfg(test)] mod test { use std::cell::RefCell; @@ -259,7 +274,6 @@ mod test { sc.grow(); - assert_eq!(sc.new_nodes.len(), 0); assert!(sc .attractors .iter() From cb9df9e79acec58147f1b93447b1a6a385a4aac2 Mon Sep 17 00:00:00 2001 From: jeangab Date: Tue, 8 Aug 2023 14:34:01 -0400 Subject: [PATCH 02/11] update cargo.lock to fix build --- Cargo.lock | 786 ++++++++++++++++++++++++++++------------------------- 1 file changed, 421 insertions(+), 365 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b9748e4..99cf8c3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,19 +4,19 @@ version = 3 [[package]] name = "actix-codec" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57a7559404a7f3573127aab53c08ce37a6c6a315c374a31070f3c91cd1b4a7fe" +checksum = "617a8268e3537fe1d8c9ead925fca49ef6400927ee7bc26750e90ecee14ce4b8" dependencies = [ - "bitflags", + "bitflags 1.3.2", "bytes 1.4.0", "futures-core", "futures-sink", - "log", "memchr", "pin-project-lite", "tokio", "tokio-util", + "tracing", ] [[package]] @@ -30,7 +30,7 @@ dependencies = [ "actix-utils", "actix-web", "askama_escape", - "bitflags", + "bitflags 1.3.2", "bytes 1.4.0", "derive_more", "futures-core", @@ -53,8 +53,8 @@ dependencies = [ "actix-service", "actix-utils", "ahash 0.8.3", - "base64 0.21.0", - "bitflags", + "base64 0.21.2", + "bitflags 1.3.2", "brotli", "bytes 1.4.0", "bytestring", @@ -83,12 +83,12 @@ dependencies = [ [[package]] name = "actix-macros" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "465a6172cf69b960917811022d8f29bc0b7fa1398bc4f78b3c466673db1213b6" +checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 1.0.109", + "syn 2.0.28", ] [[package]] @@ -206,6 +206,15 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "addr2line" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +dependencies = [ + "gimli", +] + [[package]] name = "adler" version = "1.0.2" @@ -237,9 +246,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "0.7.20" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" dependencies = [ "memchr", ] @@ -261,9 +270,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.70" +version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" +checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" [[package]] name = "askama_escape" @@ -279,18 +288,18 @@ checksum = "0e97ce7de6cf12de5d7226c73f5ba9811622f4db3a5b91b55c53e987e5f91cba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.11", + "syn 2.0.28", ] [[package]] name = "async-trait" -version = "0.1.68" +version = "0.1.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" +checksum = "cc6dde6e4ed435a4c1ee4e73592f5ba9da2151af10076cc04858746af9352d09" dependencies = [ "proc-macro2", "quote", - "syn 2.0.11", + "syn 2.0.28", ] [[package]] @@ -321,23 +330,27 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", -] - [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "backtrace" +version = "0.3.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "base64" version = "0.13.1" @@ -346,9 +359,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.0" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" +checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" [[package]] name = "bitflags" @@ -356,6 +369,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" + [[package]] name = "block-buffer" version = "0.10.4" @@ -388,9 +407,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.12.0" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" [[package]] name = "byteorder" @@ -425,17 +444,18 @@ dependencies = [ [[package]] name = "camino" -version = "1.1.4" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c530edf18f37068ac2d977409ed5cd50d53d73bc653c7647b48eb78976ac9ae2" +checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" [[package]] name = "cc" -version = "1.0.79" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "305fe645edc1442a0fa8b6726ba61d422798d37a52e12eaecf4b022ebbb88f01" dependencies = [ "jobserver", + "libc", ] [[package]] @@ -446,9 +466,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "ciborium" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c137568cc60b904a7724001b35ce2630fd00d5d84805fbb608ab89509d788f" +checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926" dependencies = [ "ciborium-io", "ciborium-ll", @@ -457,15 +477,15 @@ dependencies = [ [[package]] name = "ciborium-io" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "346de753af073cc87b52b2083a506b38ac176a44cfb05497b622e27be899b369" +checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656" [[package]] name = "ciborium-ll" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213030a2b5a4e0c0892b6652260cf6ccac84827b83a85a534e178e3906c4cf1b" +checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b" dependencies = [ "ciborium-io", "half", @@ -479,13 +499,13 @@ checksum = "186dce98367766de751c42c4f03970fc60fc012296e706ccbb9d5df9b6c1e271" [[package]] name = "colored" -version = "2.0.0" +version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" +checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6" dependencies = [ - "atty", + "is-terminal", "lazy_static", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -535,18 +555,18 @@ dependencies = [ [[package]] name = "const_format" -version = "0.2.30" +version = "0.2.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7309d9b4d3d2c0641e018d449232f2e28f1b22933c137f157d3dbc14228b8c0e" +checksum = "c990efc7a285731f9a4378d81aff2f0e85a2c8781a05ef0f8baa8dac54d0ff48" dependencies = [ "const_format_proc_macros", ] [[package]] name = "const_format_proc_macros" -version = "0.2.29" +version = "0.2.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f47bf7270cf70d370f8f98c1abb6d2d4cf60a6845d30e05bfb90c6568650" +checksum = "e026b6ce194a874cb9cf32cd5772d1ef9767cc8fcb5765948d74f37a9d8b2bf6" dependencies = [ "proc-macro2", "quote", @@ -591,15 +611,15 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "cpufeatures" -version = "0.2.6" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "280a9f2d8b3a38871a3c8a46fb80db65e5e5ed97da80c4d08bf27fb63e35e181" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" dependencies = [ "libc", ] @@ -624,14 +644,20 @@ dependencies = [ ] [[package]] -name = "derive-where" -version = "1.2.0" +name = "deranged" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b3d434edc6a4e8326087d0954b71fa7d7cc6752802b51127e0ca69b7c90b3f5" +checksum = "7684a49fb1af197853ef7b2ee694bc1f5b4179556f1e5710e1760c5db6f5e929" + +[[package]] +name = "derive-where" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bc1955a640c4464859ae700fbe48e666da6fdce99ce5fe1acd08dd295889d10" dependencies = [ "proc-macro2", "quote", - "syn 2.0.11", + "syn 2.0.28", ] [[package]] @@ -649,9 +675,9 @@ dependencies = [ [[package]] name = "digest" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", @@ -671,9 +697,9 @@ checksum = "669a445ee724c5c69b1b06fe0b63e70a1c84bc9bb7d9696cd4f4e3ec45050408" [[package]] name = "educe" -version = "0.4.20" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb0188e3c3ba8df5753894d54461f0e39bc91741dc5b22e1c46999ec2c71f4e4" +checksum = "079044df30bb07de7d846d41a184c4b00e66ebdac93ee459253474f3a47e50ae" dependencies = [ "enum-ordinalize", "proc-macro2", @@ -683,9 +709,9 @@ dependencies = [ [[package]] name = "either" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[package]] name = "encoding_rs" @@ -698,27 +724,26 @@ dependencies = [ [[package]] name = "enum-ordinalize" -version = "3.1.12" +version = "3.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bb1df8b45ecb7ffa78dca1c17a438fb193eb083db0b1b494d2a61bcb5096a" +checksum = "e4f76552f53cefc9a7f64987c3701b99d982f7690606fd67de1d09712fbf52f1" dependencies = [ "num-bigint", "num-traits", "proc-macro2", "quote", - "rustc_version", - "syn 1.0.109", + "syn 2.0.28", ] [[package]] name = "errno" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d6a0976c999d473fe89ad888d5a284e55366d9dc9038b1ba2aa15128c4afa0" +checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" dependencies = [ "errno-dragonfly", "libc", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -733,18 +758,15 @@ dependencies = [ [[package]] name = "fastrand" -version = "1.9.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] +checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" [[package]] name = "flate2" -version = "1.0.25" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" +checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" dependencies = [ "crc32fast", "miniz_oxide", @@ -773,9 +795,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" dependencies = [ "percent-encoding", ] @@ -799,9 +821,9 @@ checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678" [[package]] name = "futures" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "531ac96c6ff5fd7c62263c5e3c67a603af4fcaee2e1a0ae5565ba3a11e69e549" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" dependencies = [ "futures-channel", "futures-core", @@ -814,9 +836,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "164713a5a0dcc3e7b4b1ed7d3b433cabc18025386f9339346e8daf15963cf7ac" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" dependencies = [ "futures-core", "futures-sink", @@ -824,9 +846,9 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86d7a0c1aa76363dac491de0ee99faf6941128376f1cf96f07db7603b7de69dd" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" [[package]] name = "futures-cpupool" @@ -840,9 +862,9 @@ dependencies = [ [[package]] name = "futures-executor" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1997dd9df74cdac935c76252744c1ed5794fac083242ea4fe77ef3ed60ba0f83" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" dependencies = [ "futures-core", "futures-task", @@ -851,38 +873,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d422fa3cbe3b40dca574ab087abb5bc98258ea57eea3fd6f1fa7162c778b91" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" [[package]] name = "futures-macro" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eb14ed937631bd8b8b8977f2c198443447a8355b6e3ca599f38c975e5a963b6" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.28", ] [[package]] name = "futures-sink" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec93083a4aecafb2a80a885c9de1f0ccae9dbd32c2bb54b0c3a65690e0b8d2f2" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" [[package]] name = "futures-task" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd65540d33b37b16542a0438c12e6aeead10d4ac5d05bd3f805b8f35ab592879" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" [[package]] name = "futures-util" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ef6b17e481503ec85211fed8f39d1970f128935ca1f814cd32ac4a6842e84ab" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ "futures-channel", "futures-core", @@ -908,9 +930,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.8" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", "js-sys", @@ -919,6 +941,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "gimli" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" + [[package]] name = "gloo-net" version = "0.2.6" @@ -941,9 +969,9 @@ dependencies = [ [[package]] name = "gloo-utils" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8e8fc851e9c7b9852508bc6e3f690f452f474417e8545ec9857b7f7377036b5" +checksum = "037fcb07216cb3a30f7292bd0176b050b7b9a052ba830ef7d5d65f6dc64ba58e" dependencies = [ "js-sys", "serde", @@ -954,9 +982,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.16" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be7b54589b581f624f566bf5d8eb2bab1db736c51528720b6bd36b96b55924d" +checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" dependencies = [ "bytes 1.4.0", "fnv", @@ -988,27 +1016,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.1.19" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "hermit-abi" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] - -[[package]] -name = "hermit-abi" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" [[package]] name = "html-escape" @@ -1061,9 +1071,9 @@ checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" [[package]] name = "hyper" -version = "0.14.25" +version = "0.14.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc5e554ff619822309ffd57d8734d77cd5ce6238bc956f037ea06c58238c9899" +checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" dependencies = [ "bytes 1.4.0", "futures-channel", @@ -1098,9 +1108,9 @@ dependencies = [ [[package]] name = "idna" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -1116,32 +1126,12 @@ dependencies = [ "hashbrown", ] -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - [[package]] name = "interpolator" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1482d8bbb520daf94c82af87f38cd27cdb3073c6fee7c5805fd2fa9d3a36d494" -[[package]] -name = "io-lifetimes" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09270fd4fa1111bc614ed2246c7ef56239a3063d5be0d1ec3b589c505d400aeb" -dependencies = [ - "hermit-abi 0.3.1", - "libc", - "windows-sys 0.45.0", -] - [[package]] name = "iovec" version = "0.1.4" @@ -1153,9 +1143,20 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.7.2" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f" +checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" + +[[package]] +name = "is-terminal" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +dependencies = [ + "hermit-abi", + "rustix", + "windows-sys 0.48.0", +] [[package]] name = "itertools" @@ -1168,9 +1169,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.6" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "jobserver" @@ -1215,9 +1216,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "leptos" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dcb21804ff64f5c9d60a30a3807345db41e895bfbad17d46613c03732c17cfa" +checksum = "3a186fecd73b710a0405f81e84044c2a301198d0cf0e752a0d99df12c55eea1b" dependencies = [ "cfg-if", "leptos_config", @@ -1232,12 +1233,12 @@ dependencies = [ [[package]] name = "leptos_actix" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a24b3c327fbd930b44cd72081a53c9c08397ca48c76f6dac106f91cf3bc157e" +checksum = "ca6222cec91ca53122d8280fed6cd6b936c3299f7c35b62878f6ccc621a91a3e" dependencies = [ "actix-web", - "futures 0.3.27", + "futures 0.3.28", "leptos", "leptos_integration_utils", "leptos_meta", @@ -1248,9 +1249,9 @@ dependencies = [ [[package]] name = "leptos_config" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de88bcabd502a6071f4661a43576e4217cd4e5015086ed0c5758496a24b88c2" +checksum = "e83666404adc371296d54dcc5f36ea2a11dd865f6409596e8ecbadc287dae75b" dependencies = [ "config", "fs", @@ -1262,15 +1263,15 @@ dependencies = [ [[package]] name = "leptos_dom" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ec333aca4c8ec084608c114a8981a954d058f5b546360c7e47c79c7da4ce348" +checksum = "5e41f33273f55552aa52a776b0f14a72a466c40b23d47d6fe251b05cc6bfe9c3" dependencies = [ "async-recursion", "cfg-if", "drain_filter_polyfill", "educe", - "futures 0.3.27", + "futures 0.3.28", "html-escape", "indexmap", "itertools", @@ -1290,9 +1291,9 @@ dependencies = [ [[package]] name = "leptos_hot_reload" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39d5a2a9428d0da3b8941305bd87faf92dd77f3045768024da715030c4eb40c6" +checksum = "d85b0935d1439780ddabc4809dd2ae93a1825e9d05b95c9812942b3fc858ff9e" dependencies = [ "anyhow", "camino", @@ -1308,11 +1309,11 @@ dependencies = [ [[package]] name = "leptos_integration_utils" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4f3b8a9a11481037b85ff33e3f581e8e1afdcb21e3d2d824d6b878164ffb49" +checksum = "c70d0be0904954bf4e3a38a348845825800f8844c3990fd47463a95e3977e1e4" dependencies = [ - "futures 0.3.27", + "futures 0.3.28", "leptos", "leptos_config", "leptos_hot_reload", @@ -1321,9 +1322,9 @@ dependencies = [ [[package]] name = "leptos_macro" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6020944cf48c6ebba71723298c9e9584df92bed3ee358a6e1caebf6d18c292c" +checksum = "10d6349980934cc3b58b24d28e5c9a1e18108dd0aadef149d0615e1833d4dcd0" dependencies = [ "attribute-derive", "cfg-if", @@ -1343,9 +1344,9 @@ dependencies = [ [[package]] name = "leptos_meta" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a6143a14fc2e6efd7ca757087dc53b90dbbfa5894420f9f6cba99a7478e172" +checksum = "950533f057299e75f48471211dc9b46e0d00c640fd14bda92c34e2705add7b8d" dependencies = [ "cfg-if", "leptos", @@ -1356,13 +1357,13 @@ dependencies = [ [[package]] name = "leptos_reactive" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2e740411ce3a6bce88d7e3724f9544408885a5cd29dd41f998be2e51dbb0fca" +checksum = "22e702730c3ac1f8a619bf2b139e650b792c96c66f2285a88a1c92c1a53ed262" dependencies = [ - "base64 0.21.0", + "base64 0.21.2", "cfg-if", - "futures 0.3.27", + "futures 0.3.28", "indexmap", "js-sys", "rustc-hash", @@ -1380,9 +1381,9 @@ dependencies = [ [[package]] name = "leptos_router" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "443669ca496573d42cc9ae6454082347336b7f918ebfaaeb7ba2443b7d2f7cf8" +checksum = "214fca795824160eac59a0168607f3ff14ab09390a62938ee26e7ef077f27536" dependencies = [ "cfg-if", "common_macros", @@ -1406,9 +1407,9 @@ dependencies = [ [[package]] name = "leptos_server" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3bfbd354bd39967f0a9bed6fe9702f248c5953fa11048d272513571c47113ad" +checksum = "0ba9c15e2e49ac38980446d199cd1a672cba9363c71aa9d565605cb77e1ca3e5" dependencies = [ "lazy_static", "leptos_reactive", @@ -1441,9 +1442,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.140" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "linear-map" @@ -1459,9 +1460,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.3.0" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd550e73688e6d578f0ac2119e32b797a327631a42f9433e59d02e139c8df60d" +checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" [[package]] name = "local-channel" @@ -1483,9 +1484,9 @@ checksum = "e34f76eb3611940e0e7d53a9aaa4e6a3151f69541a282fd0dad5571420c53ff1" [[package]] name = "lock_api" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" dependencies = [ "autocfg", "scopeguard", @@ -1493,12 +1494,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.17" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" [[package]] name = "memchr" @@ -1530,23 +1528,23 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.6.2" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" dependencies = [ "adler", ] [[package]] name = "mio" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" +checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc", "log", "wasi", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -1600,20 +1598,20 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" dependencies = [ "autocfg", ] [[package]] name = "num_cpus" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.2.6", + "hermit-abi", "libc", ] @@ -1627,18 +1625,27 @@ dependencies = [ ] [[package]] -name = "once_cell" -version = "1.17.1" +name = "object" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "openssl" -version = "0.10.48" +version = "0.10.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "518915b97df115dd36109bfa429a48b8f737bd05508cf9588977b599648926d2" +checksum = "729b745ad4a5575dd06a3e1af1414bd330ee561c01b3899eb584baeaa8def17e" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if", "foreign-types", "libc", @@ -1649,13 +1656,13 @@ dependencies = [ [[package]] name = "openssl-macros" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.28", ] [[package]] @@ -1666,11 +1673,10 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.83" +version = "0.9.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "666416d899cf077260dac8698d60a60b435a46d57e82acb1be3d0dad87284e5b" +checksum = "866b5f16f90776b9bb8dc1e1802ac6f0513de3a7a7465867bfbc563dc737faac" dependencies = [ - "autocfg", "cc", "libc", "pkg-config", @@ -1705,22 +1711,22 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.7" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.2.16", + "redox_syscall", "smallvec", - "windows-sys 0.45.0", + "windows-targets", ] [[package]] name = "paste" -version = "1.0.12" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "pathdiff" @@ -1730,15 +1736,15 @@ checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" [[package]] name = "percent-encoding" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "pest" -version = "2.5.6" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cbd939b234e95d72bc393d51788aec68aeeb5d51e748ca08ff3aad58cb722f7" +checksum = "1acb4a4365a13f749a93f1a094a7805e5cfa0955373a9de860d962eaa3a5fe5a" dependencies = [ "thiserror", "ucd-trie", @@ -1746,9 +1752,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.5.6" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a81186863f3d0a27340815be8f2078dd8050b14cd71913db9fbda795e5f707d7" +checksum = "666d00490d4ac815001da55838c500eafb0320019bbaa44444137c48b443a853" dependencies = [ "pest", "pest_generator", @@ -1756,22 +1762,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.5.6" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75a1ef20bf3193c15ac345acb32e26b3dc3223aff4d77ae4fc5359567683796b" +checksum = "68ca01446f50dbda87c1786af8770d535423fa8a53aec03b8f4e3d7eb10e0929" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.28", ] [[package]] name = "pest_meta" -version = "2.5.6" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e3b284b1f13a20dc5ebc90aff59a51b8d7137c221131b52a7260c08cbc1cc80" +checksum = "56af0a30af74d0445c0bf6d9d051c979b516a1a5af790d251daee76005420a48" dependencies = [ "once_cell", "pest", @@ -1780,29 +1786,29 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.0.12" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" +checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.0.12" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" +checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.28", ] [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "2c516611246607d0c04186886dbb3a754368ef82c79e9827a802c6d836dd111c" [[package]] name = "pin-utils" @@ -1812,9 +1818,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.26" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "ppv-lite86" @@ -1858,9 +1864,9 @@ dependencies = [ [[package]] name = "proc-macro-utils" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82d8be3a44b1f16d839703969bfffd7c866faf24591d2d614aa005280fd9108a" +checksum = "5c5adb6033c8bd8006dd6c0b4d27f52eb22d490484ecf7c32fa7628e34b7e363" dependencies = [ "proc-macro2", "smallvec", @@ -1868,18 +1874,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.54" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e472a104799c74b514a57226160104aa483546de37e839ec50e3c2e41dd87534" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.26" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" dependencies = [ "proc-macro2", ] @@ -1927,29 +1933,32 @@ dependencies = [ "getrandom", ] -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags", -] - [[package]] name = "redox_syscall" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] name = "regex" -version = "1.7.3" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" +checksum = "81bc1d4caf89fac26a70747fe603c130093b53c773888797a6329091246d651a" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69" dependencies = [ "aho-corasick", "memchr", @@ -1958,17 +1967,17 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.29" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" +checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" [[package]] name = "reqwest" -version = "0.11.16" +version = "0.11.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b71749df584b7f4cac2c426c127a7c785a5106cc98f7a8feb044115f0fa254" +checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" dependencies = [ - "base64 0.21.0", + "base64 0.21.2", "bytes 1.4.0", "encoding_rs", "futures-core", @@ -2006,7 +2015,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88073939a61e5b7680558e6be56b419e208420c2adb92be54921fa6b72283f1a" dependencies = [ "base64 0.13.1", - "bitflags", + "bitflags 1.3.2", "serde", ] @@ -2020,6 +2029,12 @@ dependencies = [ "ordered-multimap", ] +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + [[package]] name = "rustc-hash" version = "1.1.0" @@ -2037,23 +2052,22 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.4" +version = "0.38.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c348b5dc624ecee40108aa2922fed8bad89d7fcc2b9f8cb18f632898ac4a37f9" +checksum = "172891ebdceb05aa0005f533a6cbfca599ddd7d966f6f5d4d9b2e70478e70399" dependencies = [ - "bitflags", + "bitflags 2.3.3", "errno", - "io-lifetimes", "libc", "linux-raw-sys", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] name = "ryu" -version = "1.0.13" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] name = "same-file" @@ -2066,26 +2080,26 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.21" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" +checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" dependencies = [ - "windows-sys 0.42.0", + "windows-sys 0.48.0", ] [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "security-framework" -version = "2.8.2" +version = "2.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" +checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" dependencies = [ - "bitflags", + "bitflags 1.3.2", "core-foundation", "core-foundation-sys", "libc", @@ -2094,9 +2108,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.8.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4" +checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" dependencies = [ "core-foundation-sys", "libc", @@ -2104,15 +2118,15 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" +checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" [[package]] name = "serde" -version = "1.0.159" +version = "1.0.183" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065" +checksum = "32ac8da02677876d532745a130fc9d8e6edfa81a269b107c5b00829b91d8eb3c" dependencies = [ "serde_derive", ] @@ -2130,20 +2144,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.159" +version = "1.0.183" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585" +checksum = "aafe972d60b0b9bee71a91b92fee2d4fb3c9d7e8f6b179aa99f27203d99a4816" dependencies = [ "proc-macro2", "quote", - "syn 2.0.11", + "syn 2.0.28", ] [[package]] name = "serde_json" -version = "1.0.95" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d721eca97ac802aa7777b701877c8004d950fc142651367300d21c1cc0194744" +checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" dependencies = [ "itoa", "ryu", @@ -2164,9 +2178,9 @@ dependencies = [ [[package]] name = "server_fn" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71cc39b7061ec91f6db79a39d24419a528ce88c7d8538ec0ac6c6623cdda66cb" +checksum = "8f7e74a67ed331d9f30befd2a0c187bdc705a7063a287f337ae0420522c4425b" dependencies = [ "ciborium", "const_format", @@ -2187,9 +2201,9 @@ dependencies = [ [[package]] name = "server_fn_macro" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76842eda4d3c25d0bca96164b1d78ab761462c02421a364ddb4d4316cd30217d" +checksum = "eca31494981546bccc81a6b1972d07929a77fed59c8824a1a70d10fe8ee00c12" dependencies = [ "const_format", "proc-macro-error", @@ -2202,9 +2216,9 @@ dependencies = [ [[package]] name = "server_fn_macro_default" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55ad0f6ee60363c3dd1c42273f114076d2b20183a88c113086591a5d648d77ec" +checksum = "aab30d5671e7758ea36e88f0860fbdd7d03f8ae1840c984b6d5b14cbe77c655d" dependencies = [ "server_fn_macro", "syn 1.0.109", @@ -2223,9 +2237,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" dependencies = [ "cfg-if", "cpufeatures", @@ -2243,11 +2257,10 @@ dependencies = [ [[package]] name = "simple_logger" -version = "4.1.0" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e78beb34673091ccf96a8816fce8bfd30d1292c7621ca2bcb5f2ba0fae4f558d" +checksum = "2230cd5c29b815c9b699fb610b49a5ed65588f3509d9f0108be3a885da629333" dependencies = [ - "atty", "colored", "log", "time", @@ -2275,9 +2288,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" [[package]] name = "socket2" @@ -2302,9 +2315,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.11" +version = "2.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21e3787bb71465627110e7d87ed4faaa36c1f61042ee67badb9e2ef173accc40" +checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" dependencies = [ "proc-macro2", "quote", @@ -2325,43 +2338,44 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.5.0" +version = "3.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" +checksum = "dc02fddf48964c42031a0b3fe0428320ecf3a73c401040fc0096f97794310651" dependencies = [ "cfg-if", "fastrand", - "redox_syscall 0.3.5", + "redox_syscall", "rustix", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] name = "thiserror" -version = "1.0.40" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.40" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" dependencies = [ "proc-macro2", "quote", - "syn 2.0.11", + "syn 2.0.28", ] [[package]] name = "time" -version = "0.3.20" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890" +checksum = "b0fdd63d58b18d663fbdf70e049f00a22c8e42be082203be7f26589213cd75ea" dependencies = [ + "deranged", "itoa", "libc", "num_threads", @@ -2372,15 +2386,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" +checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" [[package]] name = "time-macros" -version = "0.2.8" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36" +checksum = "eb71511c991639bb078fd5bf97757e03914361c48100d52878b8e52b46fb92cd" dependencies = [ "time-core", ] @@ -2402,11 +2416,12 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.27.0" +version = "1.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0de47a4eecbe11f498978a9b29d792f0d2692d1dd003650c24c76510e3bc001" +checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" dependencies = [ "autocfg", + "backtrace", "bytes 1.4.0", "libc", "mio", @@ -2414,7 +2429,7 @@ dependencies = [ "pin-project-lite", "signal-hook-registry", "socket2", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -2429,9 +2444,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.7" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2" +checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" dependencies = [ "bytes 1.4.0", "futures-core", @@ -2471,20 +2486,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.23" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" +checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.28", ] [[package]] name = "tracing-core" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" dependencies = [ "once_cell", ] @@ -2514,9 +2529,9 @@ checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" [[package]] name = "ucd-trie" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" [[package]] name = "unicase" @@ -2535,9 +2550,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.8" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" [[package]] name = "unicode-normalization" @@ -2562,9 +2577,9 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" [[package]] name = "url" -version = "2.3.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" dependencies = [ "form_urlencoded", "idna", @@ -2579,9 +2594,9 @@ checksum = "5190c9442dcdaf0ddd50f37420417d219ae5261bbf5db120d0f9bab996c9cba1" [[package]] name = "uuid" -version = "1.3.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1674845326ee10d37ca60470760d4288a6f80f304007d92e5c53bab78c9cfd79" +checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" dependencies = [ "getrandom", ] @@ -2610,11 +2625,10 @@ dependencies = [ [[package]] name = "want" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" dependencies = [ - "log", "try-lock", ] @@ -2737,37 +2751,37 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", ] [[package]] name = "windows-sys" -version = "0.45.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" -version = "0.42.2" +version = "0.48.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", ] [[package]] @@ -2776,42 +2790,84 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + [[package]] name = "windows_aarch64_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + [[package]] name = "windows_i686_gnu" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + [[package]] name = "windows_i686_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + [[package]] name = "windows_x86_64_gnu" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + [[package]] name = "windows_x86_64_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + [[package]] name = "winreg" version = "0.10.1" @@ -2838,18 +2894,18 @@ dependencies = [ [[package]] name = "zstd" -version = "0.12.3+zstd.1.5.2" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76eea132fb024e0e13fd9c2f5d5d595d8a967aa72382ac2f9d39fcc95afd0806" +checksum = "1a27595e173641171fc74a1232b7b1c7a7cb6e18222c11e9dfb9888fa424c53c" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "6.0.4+zstd.1.5.4" +version = "6.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7afb4b54b8910cf5447638cb54bf4e8a65cbedd783af98b98c62ffe91f185543" +checksum = "ee98ffd0b48ee95e6c5168188e44a54550b1564d9d530ee21d5f0eaed1069581" dependencies = [ "libc", "zstd-sys", @@ -2857,9 +2913,9 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "2.0.7+zstd.1.5.4" +version = "2.0.8+zstd.1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94509c3ba2fe55294d752b79842c530ccfab760192521df74a081a78d2b3c7f5" +checksum = "5556e6ee25d32df2586c098bbfa278803692a20d0ab9565e049480d52707ec8c" dependencies = [ "cc", "libc", From 66e1f813cf94e054f16df3bce7632142847e8033 Mon Sep 17 00:00:00 2001 From: jeangab Date: Tue, 8 Aug 2023 23:33:34 -0400 Subject: [PATCH 03/11] wip: Refactor space colonization, separate nodes vec from space colonization struct allows for simpler ownership management --- src/components/background.rs | 9 +- src/space_colonization/math.rs | 8 +- src/space_colonization/mod.rs | 7 +- src/space_colonization/space_colonization.rs | 132 ++++++------------- 4 files changed, 55 insertions(+), 101 deletions(-) diff --git a/src/components/background.rs b/src/components/background.rs index fb56834..35c171b 100644 --- a/src/components/background.rs +++ b/src/components/background.rs @@ -5,6 +5,7 @@ use wasm_bindgen::JsValue; use web_sys::window; use crate::space_colonization::Node; +use crate::space_colonization::Point; use crate::space_colonization::SpaceColonization; #[component] @@ -19,6 +20,8 @@ pub fn Background(cx: Scope, class: &'static str) -> impl IntoView { canvas.set_width(u32::try_from(width).unwrap()); canvas.set_height(u32::try_from(height).unwrap()); let mut sc = SpaceColonization::new(width.try_into().unwrap(), height.try_into().unwrap()); + let mut nodes = Vec::new(); + nodes.push(Node::new(Point::new((100, 100)))); // TODO Resize on window resize log!( "TODO resize on window resize canvas parent size = {} {}", @@ -44,7 +47,7 @@ pub fn Background(cx: Scope, class: &'static str) -> impl IntoView { context.line_to(child.position.x.into(), child.position.y.into()); }; let render_id = window().unwrap().performance().unwrap().now(); - sc.render_nodes(render_id, render_node_fn); + sc.render_nodes(&nodes, render_id, render_node_fn); context.stroke(); context.set_fill_style(&JsValue::from("magenta")); @@ -59,10 +62,10 @@ pub fn Background(cx: Scope, class: &'static str) -> impl IntoView { ); for _i in 1..150 { - sc.grow(); + nodes = sc.grow(nodes); let render_id = window().unwrap().performance().unwrap().now(); context.begin_path(); - sc.render_nodes(render_id, render_node_fn); + sc.render_nodes(&nodes, render_id, render_node_fn); context.stroke(); } }); diff --git a/src/space_colonization/math.rs b/src/space_colonization/math.rs index 756dfd3..15c266e 100644 --- a/src/space_colonization/math.rs +++ b/src/space_colonization/math.rs @@ -30,7 +30,8 @@ mod tests { #[test] fn new_node_moves_toward_single_attractor() { let growth_cell = GrowthCell::from_positions([(0, 0), (0, 10)].to_vec()); - let point = calculate_new_node_position(&growth_cell.as_refs(), SEGMENT_LENGTH); + + let point = calculate_new_node_position(&(growth_cell.node, growth_cell.attractors.iter().collect()), SEGMENT_LENGTH); assert_eq!(point, Point::new((0, 5))); } @@ -48,6 +49,7 @@ mod tests { let node = Node { position: Point::new(positions[0]), children: Vec::new().into(), + growing: true, }; let mut attractors = Vec::new(); for p in positions.iter().skip(1) { @@ -58,9 +60,5 @@ mod tests { } Self { node, attractors } } - - fn as_refs(&self) -> (Node, Vec<&Attractor>) { - (self.node, self.attractors.iter().collect()) - } } } diff --git a/src/space_colonization/mod.rs b/src/space_colonization/mod.rs index b84f929..a336ca2 100644 --- a/src/space_colonization/mod.rs +++ b/src/space_colonization/mod.rs @@ -66,17 +66,16 @@ impl Node { where F: Copy + Fn(&Node, &Node), { - let children = self.children; - for child in children.iter() { + for child in self.children.iter() { render_fn(self, &child); } - for child in children.iter() { + for child in self.children.iter() { child.render(render_id, render_fn); } } - fn new(position: Point) -> Self { + pub fn new(position: Point) -> Self { Self { position, growing: true, diff --git a/src/space_colonization/space_colonization.rs b/src/space_colonization/space_colonization.rs index 718850f..1b79742 100644 --- a/src/space_colonization/space_colonization.rs +++ b/src/space_colonization/space_colonization.rs @@ -39,29 +39,11 @@ pub struct SpaceColonization { /// /// If density is 10, then there will be an average distance of 10 between attractors density: i32, - /// Tree of all nodes in the space. There can be multiple root nodes. - /// ```yaml - /// [ - /// node: { - /// position: (x,y), - /// children : [ - /// child1 : { - /// position, children: [ grand-child1, grand-child2 ] - /// }, - /// child2 : {...} - /// ], - /// }, - /// node2: { ...another tree }, - /// ] - /// ``` - nodes: Vec, pub attractors: Vec, } impl SpaceColonization { pub fn new(width: i32, height: i32) -> SpaceColonization { - let mut nodes_vec = Vec::new(); - nodes_vec.push(Node::new(Point::new((100, 100)))); let attractors = Vec::new(); let mut sc = SpaceColonization { @@ -73,7 +55,6 @@ impl SpaceColonization { attraction_distance: 100, segment_length: 5, density: 30, - nodes: nodes_vec, attractors, }; @@ -86,7 +67,6 @@ impl SpaceColonization { pub fn new_for_tests( width: i32, height: i32, - nodes: Vec, attractors: Vec, ) -> SpaceColonization { SpaceColonization { @@ -98,17 +78,16 @@ impl SpaceColonization { attraction_distance: 12, segment_length: 3, density: 3, - nodes, attractors, } } - pub fn render_nodes(&self, render_id: f64, render_fn: F) + pub fn render_nodes(&self, nodes: &Vec, render_id: f64, render_fn: F) where F: Copy + Fn(&Node, &Node), { - info!("Rendering {} nodes", self.nodes.len()); - for n in self.nodes.iter() { + info!("Rendering {} nodes", nodes.len()); + for n in nodes.iter() { n.render(render_id, render_fn); } } @@ -153,7 +132,7 @@ impl SpaceColonization { } } - pub fn grow(&mut self) { + pub fn grow(&mut self, nodes: Vec) -> Vec { // TODO // [x] Find a clean API that will be stable across refactoring // [ ] Write the test against this api including performance @@ -163,62 +142,43 @@ impl SpaceColonization { // - I can efficiently render my nodes on a canvas // - I use as little memory as possible // - I can update my nodes - self.grow_nodes(); + self.grow_nodes(nodes) } - pub fn grow_nodes(&mut self) { + pub fn grow_nodes(&mut self, nodes: Vec) -> Vec{ // iterate through attractors // find closest node within attraction range // build a map of nodes to affecting attractors // attractors within the attraction range that this node is the closest to // // calculate new node position - let mut growing_paths: HashMap<*mut Node, Vec<&Attractor>> = HashMap::new(); - let mut influence_map = self.get_closest_node_for_attractors(); - /* - for growth_cell in growing_paths { - let position = calculate_new_node_position(&growth_cell, self.segment_length); - for a in growth_cell.1 { - if position.distance(&a.position) < self.kill_distance as f64 { - a.dead = true; - } - } - } - */ - } + let mut influence_map: HashMap<&Attractor, (*mut Node, f64)> = HashMap::new(); - fn get_closest_node_for_attractors(&self) -> HashMap<&Attractor, (&Node, f64)> { - let mut map = HashMap::new(); - self.build_attractor_map(&self.nodes, map); - - - - map - } - - // TODO use a struct instead of (&Node, f64) tuple - fn build_attractor_map<'a>(self, nodes: &'a Vec, mut map: HashMap<&'a Attractor, (&'a Node, f64)>) { - for n in nodes.iter() { + let nodes = nodes.into_iter().map(|mut n| { if !n.growing { - continue; - } - // TODO figure out that borrowing mess - let attractors: Vec<(&Attractor, f64)> = self.find_attractors_in_range(n); - if attractors.is_empty() { - n.growing = false; - continue; + return n; } - for a in attractors { - if let Some(closest) = map.get(a.0) { + let attractors_in_range = self.find_attractors_in_range(&n); + + if attractors_in_range.is_empty() { + n.growing = false; + return n; + } + + for a in attractors_in_range { + if let Some(closest) = influence_map.get(a.0) { if a.1 < closest.1 { - map.insert(a.0, (n, a.1)); + influence_map.insert(a.0, (&mut n, a.1)); } } else { - map.insert(a.0, (n, a.1)); + influence_map.insert(a.0, (&mut n, a.1)); } } - } + n + }).collect(); + + nodes } fn find_attractors_in_range(&self, n: &Node) -> Vec<(&Attractor, f64)> { @@ -233,16 +193,15 @@ impl SpaceColonization { } } - #[cfg(test)] mod test { use std::cell::RefCell; use super::*; - fn assert_nodes(sc: &SpaceColonization, expected_nodes: Vec<(Point, Point)>) { + fn assert_nodes(sc: &SpaceColonization, nodes: &Vec, expected_nodes: Vec<(Point, Point)>) { let rendered_nodes = RefCell::new(Vec::new()); - sc.render_nodes(0.0, |n1, n2| { + sc.render_nodes(&nodes, 0.0, |n1, n2| { rendered_nodes.borrow_mut().push((n1.position, n2.position)); }); @@ -252,7 +211,7 @@ mod test { } return line1.1.cmp(&line2.1); - }) + }); } #[test] @@ -262,34 +221,29 @@ mod test { let mut attractors = Vec::new(); attractors.push(Attractor::new((10, 0))); - let sc = SpaceColonization::new_for_tests(100, 100, nodes, attractors); + let mut sc = SpaceColonization::new_for_tests(100, 100, attractors); - assert_nodes(&sc, Vec::from([(Point::new((0,0)), Point::new((10,0)))])); + assert_nodes(&sc, &nodes, Vec::from([(Point::new((0, 0)), Point::new((10, 0)))])); assert_eq!(sc.attractors.len(), 1); - assert!(sc - .attractors - .iter() - .find(|a| a.dead == true) - .is_none()); + assert!(sc.attractors.iter().find(|a| a.dead == true).is_none()); - sc.grow(); + nodes = sc.grow(nodes); - assert!(sc - .attractors - .iter() - .find(|a| a.dead == true) - .is_none()); + assert!(sc.attractors.iter().find(|a| a.dead == true).is_none()); // TODO assert point 3,0 - sc.grow(); + nodes = sc.grow(nodes); + + assert_eq!( + sc.attractors + .iter() + .filter(|a| a.dead == true) + .collect::>() + .len(), + 1 + ); - assert_eq!(sc - .attractors - .iter() - .filter(|a| a.dead == true) - .collect::>().len(), 1); - // TODO assert nodes 3,0 and 6,0 - assert_eq!(sc.nodes.len(), 3); + assert_eq!(nodes.len(), 3); } } From e67f97058b7e039cfb8b51a5b26c91180f81a944 Mon Sep 17 00:00:00 2001 From: jeangab Date: Wed, 9 Aug 2023 23:20:05 -0400 Subject: [PATCH 04/11] refactoring works, only left to add a test and feature of ignoring dead attractors and nodes --- src/space_colonization/math.rs | 26 ++- src/space_colonization/mod.rs | 14 +- src/space_colonization/point.rs | 2 +- src/space_colonization/space_colonization.rs | 167 ++++++++++++++----- 4 files changed, 154 insertions(+), 55 deletions(-) diff --git a/src/space_colonization/math.rs b/src/space_colonization/math.rs index 15c266e..c97ea01 100644 --- a/src/space_colonization/math.rs +++ b/src/space_colonization/math.rs @@ -1,17 +1,18 @@ use super::{Attractor, Node, Point}; pub fn calculate_new_node_position( - growth_cell: &(Node, Vec<&Attractor>), + node: &Node, + attractors: &Vec<*mut Attractor>, segment_length: u16, ) -> Point { - let node = &growth_cell.0; - let attractors = &growth_cell.1; let mut attraction_sum_x = 0; let mut attraction_sum_y = 0; for a in attractors.iter() { - attraction_sum_x += a.position.x - node.position.x; - attraction_sum_y += a.position.y - node.position.y; + unsafe { + attraction_sum_x += (**a).position.x - node.position.x; + attraction_sum_y += (**a).position.y - node.position.y; + } } let point = Point { @@ -29,9 +30,14 @@ mod tests { #[test] fn new_node_moves_toward_single_attractor() { - let growth_cell = GrowthCell::from_positions([(0, 0), (0, 10)].to_vec()); - - let point = calculate_new_node_position(&(growth_cell.node, growth_cell.attractors.iter().collect()), SEGMENT_LENGTH); + let mut growth_cell = GrowthCell::from_positions([(0, 0), (0, 10)].to_vec()); + let attractors_as_ptr_mut = growth_cell.attractors_as_ptr_mut(); + + let point = calculate_new_node_position( + &growth_cell.node, + &attractors_as_ptr_mut, + SEGMENT_LENGTH, + ); assert_eq!(point, Point::new((0, 5))); } @@ -60,5 +66,9 @@ mod tests { } Self { node, attractors } } + + fn attractors_as_ptr_mut(&mut self) -> Vec<*mut Attractor> { + self.attractors.iter_mut().map(|a| { a as *mut Attractor }).collect() + } } } diff --git a/src/space_colonization/mod.rs b/src/space_colonization/mod.rs index a336ca2..dbce4f0 100644 --- a/src/space_colonization/mod.rs +++ b/src/space_colonization/mod.rs @@ -45,14 +45,24 @@ pub struct Node { pub children: Vec, } +pub struct Attraction { + node: *mut Node, + distance: f64, +} +impl Attraction { + fn new(node: &mut Node, distance: f64) -> Attraction { + Self { node, distance } + } +} + #[derive(Debug)] pub struct NodeRef { - path: Vec + path: Vec, } #[derive(Debug)] pub struct AttractorRef { - path: Vec + path: Vec, } impl std::hash::Hash for Node { diff --git a/src/space_colonization/point.rs b/src/space_colonization/point.rs index 94e39ea..43f72f9 100644 --- a/src/space_colonization/point.rs +++ b/src/space_colonization/point.rs @@ -191,7 +191,7 @@ mod tests { fn movement_does_not_overlap() { let root = Point::new((0,1)); let node = Point::new((0,0)); - assert_eq!(root.movement(node.clone(), 2), node); + assert_eq!(root.movement(node.clone(), 2), Point::new((0, -1))); } #[test] diff --git a/src/space_colonization/space_colonization.rs b/src/space_colonization/space_colonization.rs index 1b79742..0b9fcae 100644 --- a/src/space_colonization/space_colonization.rs +++ b/src/space_colonization/space_colonization.rs @@ -1,3 +1,5 @@ +use super::math::calculate_new_node_position; +use super::Attraction; use super::{Attractor, Node, Point}; use log::info; use rand::thread_rng; @@ -7,7 +9,7 @@ use std::collections::HashMap; pub struct SpaceColonization { max_point: Point, /// When a node grows within kill_distance of an attractor, the attractor is killed - kill_distance: i32, + kill_distance: f64, /// Maximum distance between an attractor and a node for the node to /// be affected by the attractor. /// @@ -51,7 +53,7 @@ impl SpaceColonization { x: width, y: height, }, - kill_distance: 5, + kill_distance: 5.0, attraction_distance: 100, segment_length: 5, density: 30, @@ -64,17 +66,13 @@ impl SpaceColonization { } #[cfg(test)] - pub fn new_for_tests( - width: i32, - height: i32, - attractors: Vec, - ) -> SpaceColonization { + pub fn new_for_tests(width: i32, height: i32, attractors: Vec) -> SpaceColonization { SpaceColonization { max_point: Point { x: width, y: height, }, - kill_distance: 5, + kill_distance: 5.0, attraction_distance: 12, segment_length: 3, density: 3, @@ -132,7 +130,7 @@ impl SpaceColonization { } } - pub fn grow(&mut self, nodes: Vec) -> Vec { + pub fn grow(&mut self, mut nodes: Vec) -> Vec { // TODO // [x] Find a clean API that will be stable across refactoring // [ ] Write the test against this api including performance @@ -142,51 +140,112 @@ impl SpaceColonization { // - I can efficiently render my nodes on a canvas // - I use as little memory as possible // - I can update my nodes - self.grow_nodes(nodes) + self.grow_nodes(&mut nodes); + nodes } - pub fn grow_nodes(&mut self, nodes: Vec) -> Vec{ + pub fn grow_nodes(&mut self, nodes: &mut Vec) { // iterate through attractors // find closest node within attraction range // build a map of nodes to affecting attractors // attractors within the attraction range that this node is the closest to // // calculate new node position - let mut influence_map: HashMap<&Attractor, (*mut Node, f64)> = HashMap::new(); - let nodes = nodes.into_iter().map(|mut n| { - if !n.growing { - return n; - } + // ------------ START OF BLOCK ---------- + // DO NOT MODIFY THE NODES VEC AFTER THIS + // We are taking raw pointers to Node to be dereferenced later, if the Vec of nodes is + // modified it will cause wrong behavior or segmentation faults and crash + let mut attractor_to_closest_node: HashMap<*mut Attractor, Attraction> = HashMap::new(); - let attractors_in_range = self.find_attractors_in_range(&n); + for n in nodes.iter_mut() { + self.build_attractor_to_closest_node(&mut attractor_to_closest_node, n); + } - if attractors_in_range.is_empty() { - n.growing = false; - return n; - } + let mut node_to_attractors: HashMap<*mut Node, Vec<*mut Attractor>> = HashMap::new(); - for a in attractors_in_range { - if let Some(closest) = influence_map.get(a.0) { - if a.1 < closest.1 { - influence_map.insert(a.0, (&mut n, a.1)); + attractor_to_closest_node + .drain() + .for_each(|(attractor, attraction)| { + let mut node_attractors = match node_to_attractors.remove(&attraction.node) { + Some(node_a) => node_a, + None => Vec::new(), + }; + node_attractors.push(attractor); + node_to_attractors.insert(attraction.node, node_attractors); + }); + + let mut dead_attractors: Vec<*mut Attractor> = Vec::new(); + node_to_attractors.iter().for_each(|(node, attractor)| { + // Unsafe is used here for two main reasons : + // + // PERFORMANCE : Using unsafe here allows to store multiple mutable references to a + // Node and save a few bytes of memory and cpu cycles to store a struct that holds + // a fake reference to the Node, such as the path in the tree, and then resolve it + // handling the Option<> every step of the way. + // + // Using a raw pointer we can Oh I actually just realised having a raw pointer deep + // in a tree of Vec that are getting pushed into might very well cause the pointer + // to become invalid when its parent gets pushed into and moved to another memory + // space + // + // Using raw fixed length arrays would solve that but its a fine line between too + // large memory usage and enough children nodes + + unsafe { + let new_node = Node::new(calculate_new_node_position( + &(**node), + attractor, + self.segment_length, + )); + attractor.iter().for_each(|a| { + if (**a).position.distance(&new_node.position) <= self.kill_distance { + dead_attractors.push(*a); + (**a).dead = true; } - } else { - influence_map.insert(a.0, (&mut n, a.1)); - } + }); + (**node).children.push(new_node); } - n - }).collect(); - - nodes + }); } - fn find_attractors_in_range(&self, n: &Node) -> Vec<(&Attractor, f64)> { + fn build_attractor_to_closest_node<'a>( + &'a mut self, + mut attractor_to_closest_node: &mut HashMap<*mut Attractor, Attraction>, + n: &mut Node, + ) { + if !n.growing { + return; + } + + let attractors_in_range = self.find_attractors_in_range(&n); + + if attractors_in_range.is_empty() { + n.growing = false; + return; + } + + for a in attractors_in_range { + if let Some(closest) = attractor_to_closest_node.get(&a.0) { + if a.1 < closest.distance { + attractor_to_closest_node.insert(a.0, Attraction::new(n, a.1)); + } + } else { + attractor_to_closest_node.insert(a.0, Attraction::new(n, a.1)); + } + } + + for child in n.children.iter_mut() { + self.build_attractor_to_closest_node(&mut attractor_to_closest_node, child); + } + } + + fn find_attractors_in_range(&mut self, n: &Node) -> Vec<(*mut Attractor, f64)> { let mut attractors_in_range = Vec::new(); - for a in self.attractors.iter() { + for a in self.attractors.iter_mut() { let distance = n.position.distance(&a.position); if distance < self.attraction_distance as f64 { - attractors_in_range.push((a, distance)); + attractors_in_range.push((a as *mut Attractor, distance)); } } attractors_in_range @@ -199,19 +258,28 @@ mod test { use super::*; - fn assert_nodes(sc: &SpaceColonization, nodes: &Vec, expected_nodes: Vec<(Point, Point)>) { + fn assert_vertices( + sc: &SpaceColonization, + nodes: &Vec, + mut expected_nodes: Vec<(Point, Point)>, + ) { let rendered_nodes = RefCell::new(Vec::new()); sc.render_nodes(&nodes, 0.0, |n1, n2| { rendered_nodes.borrow_mut().push((n1.position, n2.position)); }); - - rendered_nodes.borrow_mut().sort_by(|line1, line2| { + let sort_points = |line1: &(Point, Point), line2: &(Point, Point)| { if line1.0 != line2.0 { return line1.0.cmp(&line2.0); } return line1.1.cmp(&line2.1); - }); + }; + rendered_nodes.borrow_mut().sort_by(sort_points); + expected_nodes.sort_by(sort_points); + + let rendered_nodes = rendered_nodes.take(); + + assert_eq!(rendered_nodes, expected_nodes); } #[test] @@ -223,16 +291,30 @@ mod test { let mut sc = SpaceColonization::new_for_tests(100, 100, attractors); - assert_nodes(&sc, &nodes, Vec::from([(Point::new((0, 0)), Point::new((10, 0)))])); assert_eq!(sc.attractors.len(), 1); assert!(sc.attractors.iter().find(|a| a.dead == true).is_none()); + println!("before grow"); + dbg!(&nodes); nodes = sc.grow(nodes); + println!("after grow 1"); + dbg!(&nodes); assert!(sc.attractors.iter().find(|a| a.dead == true).is_none()); - // TODO assert point 3,0 nodes = sc.grow(nodes); + println!("after grow 2"); + dbg!(&nodes); + + // TODO assert nodes 3,0 and 6,0 + assert_vertices( + &sc, + &nodes, + Vec::from([ + (Point::new((0, 0)), Point::new((3, 0))), + (Point::new((3, 0)), Point::new((6, 0))), + ]), + ); assert_eq!( sc.attractors @@ -242,8 +324,5 @@ mod test { .len(), 1 ); - - // TODO assert nodes 3,0 and 6,0 - assert_eq!(nodes.len(), 3); } } From 62208591fc5a0e0d1f31b28d067960d0993154d9 Mon Sep 17 00:00:00 2001 From: jeangab Date: Thu, 10 Aug 2023 10:55:08 -0400 Subject: [PATCH 05/11] Its alive! Refactoring to improve performance using pointers works, now performance still sucks because there is no spatial index and there are some math bugs that create nodes way too far from home --- Cargo.lock | 24 +++++------ Cargo.toml | 2 +- src/app.rs | 2 + src/components/background.rs | 44 +++++++++++++++----- src/routes/empty/mod.rs | 2 + src/routes/empty/page.rs | 12 ++++++ src/routes/mod.rs | 1 + src/space_colonization/mod.rs | 14 +------ src/space_colonization/space_colonization.rs | 18 ++++---- 9 files changed, 74 insertions(+), 45 deletions(-) create mode 100644 src/routes/empty/mod.rs create mode 100644 src/routes/empty/page.rs diff --git a/Cargo.lock b/Cargo.lock index 99cf8c3..53ebaae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2640,9 +2640,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -2650,16 +2650,16 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.28", "wasm-bindgen-shared", ] @@ -2677,9 +2677,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2687,22 +2687,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.28", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" [[package]] name = "web-sys" diff --git a/Cargo.toml b/Cargo.toml index 4f95d55..c50aaa2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ leptos_actix = { version = "0.2", optional = true } leptos_router = { version = "0.2", default-features = false } log = "0.4" simple_logger = "4" -wasm-bindgen = "=0.2.84" +wasm-bindgen = "=0.2.87" js-sys = "0.3.51" rand = "0.8.5" getrandom = { version = "0.2", features = ["js"] } diff --git a/src/app.rs b/src/app.rs index 1569139..5a494ca 100644 --- a/src/app.rs +++ b/src/app.rs @@ -2,6 +2,7 @@ use crate::components::BackgroundProps; use crate::components::Background; use crate::routes::whymdc::*; use crate::routes::home::*; +use crate::routes::empty::*; use crate::routes::blog::*; use leptos::*; use leptos_meta::*; @@ -35,6 +36,7 @@ pub fn App(cx: Scope) -> impl IntoView { }/> }/> }/> + }/> diff --git a/src/components/background.rs b/src/components/background.rs index 35c171b..a1f8acd 100644 --- a/src/components/background.rs +++ b/src/components/background.rs @@ -1,5 +1,9 @@ +use std::cell::RefCell; +use std::rc::Rc; + use leptos::html::Canvas; use leptos::*; +use wasm_bindgen::prelude::Closure; use wasm_bindgen::JsCast; use wasm_bindgen::JsValue; use web_sys::window; @@ -17,11 +21,16 @@ pub fn Background(cx: Scope, class: &'static str) -> impl IntoView { let canvas_parent = canvas.parent_element().unwrap(); let width = canvas_parent.client_width(); let height = canvas_parent.client_height(); - canvas.set_width(u32::try_from(width).unwrap()); - canvas.set_height(u32::try_from(height).unwrap()); + let window_width = u32::try_from(width).unwrap(); + let window_height = u32::try_from(height).unwrap(); + canvas.set_width(window_width); + canvas.set_height(window_height); let mut sc = SpaceColonization::new(width.try_into().unwrap(), height.try_into().unwrap()); - let mut nodes = Vec::new(); - nodes.push(Node::new(Point::new((100, 100)))); + let nodes = Rc::new(RefCell::new(Vec::new())); + nodes.borrow_mut().push(Node::new(Point::new(( + (window_width / 2) as i32, + (window_height / 2) as i32, + )))); // TODO Resize on window resize log!( "TODO resize on window resize canvas parent size = {} {}", @@ -47,7 +56,7 @@ pub fn Background(cx: Scope, class: &'static str) -> impl IntoView { context.line_to(child.position.x.into(), child.position.y.into()); }; let render_id = window().unwrap().performance().unwrap().now(); - sc.render_nodes(&nodes, render_id, render_node_fn); + sc.render_nodes(&nodes.borrow(), render_id, render_node_fn); context.stroke(); context.set_fill_style(&JsValue::from("magenta")); @@ -60,14 +69,29 @@ pub fn Background(cx: Scope, class: &'static str) -> impl IntoView { sc.attractors.len(), end_time - start_time ); - - for _i in 1..150 { - nodes = sc.grow(nodes); + let context = context.clone(); + let closure = Closure::::new(move |_: web_sys::MouseEvent| { + let start_time = window().unwrap().performance().unwrap().now(); + let render_node_fn = |n: &Node, child: &Node| { + context.move_to(n.position.x.into(), n.position.y.into()); + context.line_to(child.position.x.into(), child.position.y.into()); + }; + sc.grow(&mut nodes.borrow_mut()); let render_id = window().unwrap().performance().unwrap().now(); context.begin_path(); - sc.render_nodes(&nodes, render_id, render_node_fn); + sc.render_nodes(&nodes.borrow(), render_id, render_node_fn); context.stroke(); - } + let end_time = window().unwrap().performance().unwrap().now(); + log!( + "Rendering nodes and {} attractors took {}", + sc.attractors.len(), + end_time - start_time + ); + }); + + let window = window().unwrap(); + window.add_event_listener_with_callback("click", closure.as_ref().unchecked_ref()).unwrap(); + closure.forget(); }); let class = format!("canvas {}", class); diff --git a/src/routes/empty/mod.rs b/src/routes/empty/mod.rs new file mode 100644 index 0000000..f5f67f8 --- /dev/null +++ b/src/routes/empty/mod.rs @@ -0,0 +1,2 @@ +mod page; +pub use page::*; diff --git a/src/routes/empty/page.rs b/src/routes/empty/page.rs new file mode 100644 index 0000000..39dc4bd --- /dev/null +++ b/src/routes/empty/page.rs @@ -0,0 +1,12 @@ +use leptos::*; +use leptos_meta::*; + +/// Renders the home page of your application. +#[component] +pub fn Empty(cx: Scope) -> impl IntoView { + view! { cx, + + <div class=""> + </div> + } +} diff --git a/src/routes/mod.rs b/src/routes/mod.rs index 1bfe892..22d4b35 100644 --- a/src/routes/mod.rs +++ b/src/routes/mod.rs @@ -1,3 +1,4 @@ pub mod whymdc; pub mod home; pub mod blog; +pub mod empty; diff --git a/src/space_colonization/mod.rs b/src/space_colonization/mod.rs index dbce4f0..b10e132 100644 --- a/src/space_colonization/mod.rs +++ b/src/space_colonization/mod.rs @@ -19,9 +19,9 @@ pub struct Attractor { } impl Attractor { - pub fn new(position: (i32, i32)) -> Attractor { + pub fn new(position: Point) -> Attractor { Attractor { - position: Point::new(position), + position, dead: false, } } @@ -55,16 +55,6 @@ impl Attraction { } } -#[derive(Debug)] -pub struct NodeRef { - path: Vec<u16>, -} - -#[derive(Debug)] -pub struct AttractorRef { - path: Vec<u16>, -} - impl std::hash::Hash for Node { fn hash<H: std::hash::Hasher>(&self, state: &mut H) { self.position.hash(state); diff --git a/src/space_colonization/space_colonization.rs b/src/space_colonization/space_colonization.rs index 0b9fcae..5a776ed 100644 --- a/src/space_colonization/space_colonization.rs +++ b/src/space_colonization/space_colonization.rs @@ -95,10 +95,9 @@ impl SpaceColonization { let mut y_pos = 0; while x_pos < self.max_point.x { while y_pos < self.max_point.y { - self.attractors.push(Attractor { - position: self.get_random_point(x_pos.into(), y_pos.into()), - dead: false, - }); + self.attractors.push(Attractor::new( + self.get_random_point(x_pos.into(), y_pos.into()), + )); y_pos += self.density; } x_pos += self.density; @@ -130,7 +129,7 @@ impl SpaceColonization { } } - pub fn grow(&mut self, mut nodes: Vec<Node>) -> Vec<Node> { + pub fn grow<'a>(&mut self, mut nodes: &'a mut Vec<Node>) { // TODO // [x] Find a clean API that will be stable across refactoring // [ ] Write the test against this api including performance @@ -140,8 +139,7 @@ impl SpaceColonization { // - I can efficiently render my nodes on a canvas // - I use as little memory as possible // - I can update my nodes - self.grow_nodes(&mut nodes); - nodes + self.grow_nodes(&mut nodes) } pub fn grow_nodes(&mut self, nodes: &mut Vec<Node>) { @@ -287,7 +285,7 @@ mod test { let mut nodes = Vec::new(); nodes.push(Node::new(Point::new((0, 0)))); let mut attractors = Vec::new(); - attractors.push(Attractor::new((10, 0))); + attractors.push(Attractor::new(Point::new((10, 0)))); let mut sc = SpaceColonization::new_for_tests(100, 100, attractors); @@ -296,13 +294,13 @@ mod test { println!("before grow"); dbg!(&nodes); - nodes = sc.grow(nodes); + sc.grow(&mut nodes); println!("after grow 1"); dbg!(&nodes); assert!(sc.attractors.iter().find(|a| a.dead == true).is_none()); - nodes = sc.grow(nodes); + sc.grow(&mut nodes); println!("after grow 2"); dbg!(&nodes); From 97cf5b21d9982c3280e7e473ea6de190760aef5b Mon Sep 17 00:00:00 2001 From: jeangab <jg@nationtech.io> Date: Thu, 10 Aug 2023 22:05:46 -0400 Subject: [PATCH 06/11] feat(space colonization): now pretty much works! still slowish but not too bad, about 10fps at worst on a good laptop with a ryzen 6800u --- Cargo.lock | 41 ++++ Cargo.toml | 4 + src/components/background.rs | 17 +- src/space_colonization/math.rs | 198 +++++++++++++++++-- src/space_colonization/space_colonization.rs | 64 ++++-- 5 files changed, 284 insertions(+), 40 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 53ebaae..6d6281b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -735,6 +735,19 @@ dependencies = [ "syn 2.0.28", ] +[[package]] +name = "env_logger" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + [[package]] name = "errno" version = "0.3.2" @@ -1069,6 +1082,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "hyper" version = "0.14.27" @@ -1427,6 +1446,7 @@ dependencies = [ "cfg-if", "console_error_panic_hook", "console_log", + "env_logger", "getrandom", "js-sys", "leptos", @@ -1436,6 +1456,7 @@ dependencies = [ "log", "rand", "simple_logger", + "test-log", "wasm-bindgen", "web-sys", ] @@ -2349,6 +2370,26 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "termcolor" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "test-log" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9601d162c1d77e62c1ea0bc8116cd1caf143ce3af947536c3c9052a1677fe0c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "thiserror" version = "1.0.44" diff --git a/Cargo.toml b/Cargo.toml index c50aaa2..1d0e56d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -96,3 +96,7 @@ lib-features = ["hydrate"] # # Optional. Defaults to false. lib-default-features = false + +[dev-dependencies] +test-log = "*" +env_logger = "*" diff --git a/src/components/background.rs b/src/components/background.rs index a1f8acd..16dbac1 100644 --- a/src/components/background.rs +++ b/src/components/background.rs @@ -59,10 +59,6 @@ pub fn Background(cx: Scope, class: &'static str) -> impl IntoView { sc.render_nodes(&nodes.borrow(), render_id, render_node_fn); context.stroke(); - context.set_fill_style(&JsValue::from("magenta")); - for a in sc.attractors.iter() { - context.fill_rect(a.position.x.into(), a.position.y.into(), 5.0, 5.0); - } let end_time = window().unwrap().performance().unwrap().now(); log!( "Rendering nodes and {} attractors took {}", @@ -80,6 +76,15 @@ pub fn Background(cx: Scope, class: &'static str) -> impl IntoView { let render_id = window().unwrap().performance().unwrap().now(); context.begin_path(); sc.render_nodes(&nodes.borrow(), render_id, render_node_fn); + + context.set_fill_style(&JsValue::from("magenta")); + for a in sc.attractors.iter().filter(|a| a.dead) { + context.fill_rect(a.position.x.into(), a.position.y.into(), 5.0, 5.0); + } + context.set_fill_style(&JsValue::from("red")); + for a in sc.attractors.iter().filter(|a| !a.dead) { + context.fill_rect(a.position.x.into(), a.position.y.into(), 5.0, 5.0); + } context.stroke(); let end_time = window().unwrap().performance().unwrap().now(); log!( @@ -90,7 +95,9 @@ pub fn Background(cx: Scope, class: &'static str) -> impl IntoView { }); let window = window().unwrap(); - window.add_event_listener_with_callback("click", closure.as_ref().unchecked_ref()).unwrap(); + window + .add_event_listener_with_callback("click", closure.as_ref().unchecked_ref()) + .unwrap(); closure.forget(); }); diff --git a/src/space_colonization/math.rs b/src/space_colonization/math.rs index c97ea01..98f34c2 100644 --- a/src/space_colonization/math.rs +++ b/src/space_colonization/math.rs @@ -1,26 +1,107 @@ +use log::info; + use super::{Attractor, Node, Point}; pub fn calculate_new_node_position( node: &Node, attractors: &Vec<*mut Attractor>, segment_length: u16, -) -> Point { +) -> Option<Point> { + calculate_new_node_position_with_skip(node, attractors, segment_length, 0) +} + +pub fn calculate_new_node_position_with_skip( + node: &Node, + attractors: &Vec<*mut Attractor>, + segment_length: u16, + attractors_to_skip: usize, +) -> Option<Point> { + assert!( + attractors.len() > 0, + "There must be at least one attractor!" + ); let mut attraction_sum_x = 0; let mut attraction_sum_y = 0; - for a in attractors.iter() { - unsafe { - attraction_sum_x += (**a).position.x - node.position.x; - attraction_sum_y += (**a).position.y - node.position.y; + for a in attractors.iter().skip(attractors_to_skip) { + if attractors_to_skip > 0 { + info!("working on attractor {:?}", a); } + let attractor: &Attractor; + unsafe { + attractor = &**a; + } + + if attractors_to_skip > 0 { + info!("successfully worked with attractor {:?}", a); + } + attraction_sum_x += attractor.position.x - node.position.x; + attraction_sum_y += attractor.position.y - node.position.y; + } + + // Here this fixes what happens when the sum of the vectors towards attractors is 0 + // See test new_node_ignores_attractors_when_average_results_in_no_movement + if attraction_sum_y == 0 && attraction_sum_x == 0 { + if attractors.len() == 1 { + let a = attractors.first().unwrap(); + unsafe { + (**a).dead = true; + } + return None; + } + assert!( + attractors.len() > attractors_to_skip + 1, + "There must be more attractors in the array than the number to skip" + ); + + return calculate_new_node_position_with_skip( + node, + attractors, + segment_length, + attractors_to_skip + 1, + ); } let point = Point { - x: node.position.x + attraction_sum_x / attractors.len() as i32, - y: node.position.y + attraction_sum_y / attractors.len() as i32, + x: node.position.x + attraction_sum_x as i32, + y: node.position.y + attraction_sum_y as i32, }; - node.position.movement(point, segment_length) + let new_point = node.position.movement(point, segment_length); + println!("just did movement"); + dbg!(node.position, point, segment_length, new_point); + + let new_distance = new_point.distance(&node.position); + if new_distance > (segment_length * 2) as f64 { + info!( + "new node {:?} is far from parent {:?}", + new_point, node.position + ); + let mut readable_attractors: Vec<&Attractor> = Vec::new(); + unsafe { + attractors.iter().for_each(|a| { + readable_attractors.push(&**a); + }); + } + info!( + "Calculations inputs are + attractors {:?} + node.position {:?} + segment_length {} + point {:?}", + readable_attractors, node.position, segment_length, point + ); + + info!( + "Calculations outputs are + distance {} + attraction_sum x {} , y {} + new_point {:?}", + new_distance, attraction_sum_x, attraction_sum_y, new_point + ); + } + + Some(new_point) } #[cfg(test)] @@ -30,19 +111,97 @@ mod tests { #[test] fn new_node_moves_toward_single_attractor() { - let mut growth_cell = GrowthCell::from_positions([(0, 0), (0, 10)].to_vec()); - let attractors_as_ptr_mut = growth_cell.attractors_as_ptr_mut(); + let mut growth_cell = GrowthCell::from_positions((0, 0), [(0, 10)].to_vec()); + let mut attractors_as_ptr_mut = growth_cell.attractors_as_ptr_mut(); let point = calculate_new_node_position( &growth_cell.node, - &attractors_as_ptr_mut, + &mut attractors_as_ptr_mut, SEGMENT_LENGTH, - ); + ) + .unwrap(); assert_eq!(point, Point::new((0, 5))); } #[test] - fn new_node_ignores_dead_attractor() {} + fn new_node_ignores_attractors_when_average_results_in_no_movement() { + let mut growth_cell = GrowthCell::from_positions((10, 0), [(0, 0), (20, 0)].to_vec()); + let mut attractors_as_ptr_mut = growth_cell.attractors_as_ptr_mut(); + + let point = calculate_new_node_position( + &growth_cell.node, + &mut attractors_as_ptr_mut, + SEGMENT_LENGTH, + ) + .unwrap(); + assert_eq!(point, Point::new((15, 0))); + } + + #[test] + fn new_node_ignores_dead_attractor() { + // TODO + assert!(false); + } + + #[test_log::test] + fn large_number_of_attractors() { + let attractors = [ + (1048, 241), + (935, 268), + (953, 363), + (978, 333), + (988, 355), + (894, 234), + (892, 331), + (1050, 275), + (972, 261), + (882, 280), + (1013, 212), + (1023, 233), + (899, 197), + (911, 285), + (879, 291), + (977, 293), + (938, 233), + (975, 196), + (964, 295), + (967, 197), + (869, 242), + (945, 323), + (1035, 287), + (962, 243), + (1023, 297), + (952, 185), + (984, 261), + (1011, 264), + (931, 209), + (900, 281), + (1006, 319), + (929, 295), + (936, 325), + (1001, 182), + (995, 225), + ]; + let node = (960, 266); + + let mut growth_cell = GrowthCell::from_positions(node, attractors.to_vec()); + let mut attractors_as_ptr_mut = growth_cell.attractors_as_ptr_mut(); + + let point = calculate_new_node_position( + &growth_cell.node, + &mut attractors_as_ptr_mut, + SEGMENT_LENGTH, + ) + .unwrap(); + assert_eq!(point, Point::new((965, 266))); + /* + segment_length 5 + Calculations outputs are + distance 996.1706681086329 + attraction_sum x 17 , y 1 + resulting point Point { x: 960, y: 266 } + */ + } struct GrowthCell { node: Node, @@ -50,15 +209,15 @@ mod tests { } impl GrowthCell { - pub fn from_positions(positions: Vec<(i32, i32)>) -> Self { - assert!(positions.len() >= 2); + pub fn from_positions(node: (i32, i32), attractors_positions: Vec<(i32, i32)>) -> Self { + assert!(attractors_positions.len() >= 1); let node = Node { - position: Point::new(positions[0]), + position: Point::new(node), children: Vec::new().into(), growing: true, }; let mut attractors = Vec::new(); - for p in positions.iter().skip(1) { + for p in attractors_positions.iter() { attractors.push(Attractor { position: Point::new(*p), dead: false, @@ -68,7 +227,10 @@ mod tests { } fn attractors_as_ptr_mut(&mut self) -> Vec<*mut Attractor> { - self.attractors.iter_mut().map(|a| { a as *mut Attractor }).collect() + self.attractors + .iter_mut() + .map(|a| a as *mut Attractor) + .collect() } } } diff --git a/src/space_colonization/space_colonization.rs b/src/space_colonization/space_colonization.rs index 5a776ed..6db52fe 100644 --- a/src/space_colonization/space_colonization.rs +++ b/src/space_colonization/space_colonization.rs @@ -139,6 +139,7 @@ impl SpaceColonization { // - I can efficiently render my nodes on a canvas // - I use as little memory as possible // - I can update my nodes + info!("Growing nodes {:?}", nodes); self.grow_nodes(&mut nodes) } @@ -189,20 +190,29 @@ impl SpaceColonization { // // Using raw fixed length arrays would solve that but its a fine line between too // large memory usage and enough children nodes + // + // LEARNING : using unsafe here sounded like not the worst idea and was a nice + // opportunity to learn, which did happen. I am closing in now and I can say that I + // have learned quite a lot about how rust programs work and should be designed. unsafe { - let new_node = Node::new(calculate_new_node_position( - &(**node), - attractor, - self.segment_length, - )); - attractor.iter().for_each(|a| { - if (**a).position.distance(&new_node.position) <= self.kill_distance { - dead_attractors.push(*a); - (**a).dead = true; - } - }); - (**node).children.push(new_node); + /* + let segfault_boy: *const u8 = usize::MAX as *const u8; + let memory_content = *segfault_boy; + println!("memory content at address 0 {}", memory_content); + */ + let new_point = + calculate_new_node_position(&(**node), attractor, self.segment_length); + if let Some(new_point) = new_point { + let new_node = Node::new(new_point); + attractor.iter().for_each(|a| { + if (**a).position.distance(&new_node.position) <= self.kill_distance { + dead_attractors.push(*a); + (**a).dead = true; + } + }); + (**node).children.push(new_node); + } } }); } @@ -212,6 +222,10 @@ impl SpaceColonization { mut attractor_to_closest_node: &mut HashMap<*mut Attractor, Attraction>, n: &mut Node, ) { + for child in n.children.iter_mut() { + self.build_attractor_to_closest_node(&mut attractor_to_closest_node, child); + } + if !n.growing { return; } @@ -233,14 +247,11 @@ impl SpaceColonization { } } - for child in n.children.iter_mut() { - self.build_attractor_to_closest_node(&mut attractor_to_closest_node, child); - } } fn find_attractors_in_range(&mut self, n: &Node) -> Vec<(*mut Attractor, f64)> { let mut attractors_in_range = Vec::new(); - for a in self.attractors.iter_mut() { + for a in self.attractors.iter_mut().filter(|a| !a.dead) { let distance = n.position.distance(&a.position); if distance < self.attraction_distance as f64 { attractors_in_range.push((a as *mut Attractor, distance)); @@ -304,7 +315,6 @@ mod test { println!("after grow 2"); dbg!(&nodes); - // TODO assert nodes 3,0 and 6,0 assert_vertices( &sc, &nodes, @@ -323,4 +333,24 @@ mod test { 1 ); } + + #[test] + fn grow_should_ignore_dead_attractors() { + let mut nodes = Vec::new(); + nodes.push(Node::new(Point::new((0, 0)))); + let mut attractors = Vec::new(); + attractors.push(Attractor { + position: Point::new((10, 0)), + dead: true, + }); + + let mut sc = SpaceColonization::new_for_tests(100, 100, attractors); + + assert_eq!(sc.attractors.len(), 1); + assert!(sc.attractors.iter().find(|a| a.dead == true).is_some()); + + sc.grow(&mut nodes); + + assert_vertices(&sc, &nodes, Vec::new()); + } } From c4cbef68d96f58d3061a7d3e2c97f08172890f40 Mon Sep 17 00:00:00 2001 From: jeangab <jg@nationtech.io> Date: Fri, 11 Aug 2023 11:55:48 -0400 Subject: [PATCH 07/11] feat(space colonization): Only render new node when it is created, should improve performance instead of rerendering every node on every tick --- src/components/background.rs | 72 +++++++++++++------- src/space_colonization/mod.rs | 4 +- src/space_colonization/space_colonization.rs | 65 +++++++++++------- 3 files changed, 90 insertions(+), 51 deletions(-) diff --git a/src/components/background.rs b/src/components/background.rs index 16dbac1..64923ed 100644 --- a/src/components/background.rs +++ b/src/components/background.rs @@ -25,19 +25,7 @@ pub fn Background(cx: Scope, class: &'static str) -> impl IntoView { let window_height = u32::try_from(height).unwrap(); canvas.set_width(window_width); canvas.set_height(window_height); - let mut sc = SpaceColonization::new(width.try_into().unwrap(), height.try_into().unwrap()); - let nodes = Rc::new(RefCell::new(Vec::new())); - nodes.borrow_mut().push(Node::new(Point::new(( - (window_width / 2) as i32, - (window_height / 2) as i32, - )))); - // TODO Resize on window resize - log!( - "TODO resize on window resize canvas parent size = {} {}", - canvas_parent.client_width(), - canvas_parent.client_height() - ); - log!("in canvas"); + let context = canvas .get_context("2d") .ok() @@ -46,17 +34,54 @@ pub fn Background(cx: Scope, class: &'static str) -> impl IntoView { .unchecked_into::<web_sys::CanvasRenderingContext2d>(); log!("context = {:#?}", context); context.set_stroke_style(&JsValue::from("white")); + let context_to_render = context.clone(); + // let render_node_fn : 'a Fn(&Node, &Node) = |n: &Node, child: &Node| { + let render_node_fn = move |n: &Node, child: &Node| { + context_to_render.move_to(n.position.x.into(), n.position.y.into()); + context_to_render.line_to(child.position.x.into(), child.position.y.into()); + }; + let mut sc = SpaceColonization::new(width.try_into().unwrap(), height.try_into().unwrap(), render_node_fn); + let nodes = Rc::new(RefCell::new(Vec::new())); + nodes.borrow_mut().push(Node::new(Point::new(( + (window_width / 3) as i32, + (window_height / 3) as i32, + )))); + nodes.borrow_mut().push(Node::new(Point::new(( + (window_width / 2) as i32, + (window_height / 3) as i32, + )))); + nodes.borrow_mut().push(Node::new(Point::new(( + (window_width / 3) as i32, + (window_height / 2) as i32, + )))); + nodes.borrow_mut().push(Node::new(Point::new(( + (window_width - 200) as i32, + (window_height / 3) as i32, + )))); + nodes.borrow_mut().push(Node::new(Point::new(( + (window_width - 100) as i32, + (window_height - 100) as i32, + )))); + // TODO Resize on window resize + log!( + "TODO resize on window resize canvas parent size = {} {}", + canvas_parent.client_width(), + canvas_parent.client_height() + ); + context.set_stroke_style(&JsValue::from("white")); context.set_fill_style(&JsValue::from("yellow")); log!("About to render nodes"); let start_time = window().unwrap().performance().unwrap().now(); context.begin_path(); + /* let render_node_fn = |n: &Node, child: &Node| { context.move_to(n.position.x.into(), n.position.y.into()); context.line_to(child.position.x.into(), child.position.y.into()); }; - let render_id = window().unwrap().performance().unwrap().now(); - sc.render_nodes(&nodes.borrow(), render_id, render_node_fn); + */ + // let render_id = window().unwrap().performance().unwrap().now(); + // sc.render_all_nodes(&nodes.borrow(), render_id, render_node_fn); context.stroke(); let end_time = window().unwrap().performance().unwrap().now(); @@ -68,15 +93,12 @@ pub fn Background(cx: Scope, class: &'static str) -> impl IntoView { let context = context.clone(); let closure = Closure::<dyn FnMut(_)>::new(move |_: web_sys::MouseEvent| { let start_time = window().unwrap().performance().unwrap().now(); - let render_node_fn = |n: &Node, child: &Node| { - context.move_to(n.position.x.into(), n.position.y.into()); - context.line_to(child.position.x.into(), child.position.y.into()); - }; sc.grow(&mut nodes.borrow_mut()); - let render_id = window().unwrap().performance().unwrap().now(); - context.begin_path(); - sc.render_nodes(&nodes.borrow(), render_id, render_node_fn); + // let render_id = window().unwrap().performance().unwrap().now(); + // context.begin_path(); + // sc.render_nodes(&nodes.borrow(), render_id, render_node_fn); + /* context.set_fill_style(&JsValue::from("magenta")); for a in sc.attractors.iter().filter(|a| a.dead) { context.fill_rect(a.position.x.into(), a.position.y.into(), 5.0, 5.0); @@ -85,6 +107,7 @@ pub fn Background(cx: Scope, class: &'static str) -> impl IntoView { for a in sc.attractors.iter().filter(|a| !a.dead) { context.fill_rect(a.position.x.into(), a.position.y.into(), 5.0, 5.0); } + */ context.stroke(); let end_time = window().unwrap().performance().unwrap().now(); log!( @@ -96,7 +119,10 @@ pub fn Background(cx: Scope, class: &'static str) -> impl IntoView { let window = window().unwrap(); window - .add_event_listener_with_callback("click", closure.as_ref().unchecked_ref()) + .set_interval_with_callback_and_timeout_and_arguments_0( + closure.as_ref().unchecked_ref(), + 10, + ) .unwrap(); closure.forget(); }); diff --git a/src/space_colonization/mod.rs b/src/space_colonization/mod.rs index b10e132..2d6669e 100644 --- a/src/space_colonization/mod.rs +++ b/src/space_colonization/mod.rs @@ -62,9 +62,9 @@ impl std::hash::Hash for Node { } impl Node { - pub fn render<F>(&self, render_id: f64, render_fn: F) + pub fn render<G>(&self, render_id: f64, render_fn: G) where - F: Copy + Fn(&Node, &Node), + G: Copy + Fn(&Node, &Node), { for child in self.children.iter() { render_fn(self, &child); diff --git a/src/space_colonization/space_colonization.rs b/src/space_colonization/space_colonization.rs index 6db52fe..dcb6faf 100644 --- a/src/space_colonization/space_colonization.rs +++ b/src/space_colonization/space_colonization.rs @@ -6,7 +6,10 @@ use rand::thread_rng; use rand::Rng; use std::collections::HashMap; -pub struct SpaceColonization { +pub struct SpaceColonization<F> +where + F: Fn(&Node, &Node), +{ max_point: Point, /// When a node grows within kill_distance of an attractor, the attractor is killed kill_distance: f64, @@ -42,10 +45,17 @@ pub struct SpaceColonization { /// If density is 10, then there will be an average distance of 10 between attractors density: i32, pub attractors: Vec<Attractor>, + render_fn: F, } -impl SpaceColonization { - pub fn new(width: i32, height: i32) -> SpaceColonization { +impl<F> SpaceColonization<F> +where + F: Fn(&Node, &Node), +{ + pub fn new(width: i32, height: i32, render_fn: F) -> SpaceColonization<F> + where + F: Fn(&Node, &Node), + { let attractors = Vec::new(); let mut sc = SpaceColonization { @@ -58,6 +68,7 @@ impl SpaceColonization { segment_length: 5, density: 30, attractors, + render_fn, }; sc.place_attractors(); @@ -66,7 +77,15 @@ impl SpaceColonization { } #[cfg(test)] - pub fn new_for_tests(width: i32, height: i32, attractors: Vec<Attractor>) -> SpaceColonization { + pub fn new_for_tests( + width: i32, + height: i32, + attractors: Vec<Attractor>, + render_fn: F, + ) -> SpaceColonization<F> + where + F: Fn(&Node, &Node), + { SpaceColonization { max_point: Point { x: width, @@ -77,12 +96,13 @@ impl SpaceColonization { segment_length: 3, density: 3, attractors, + render_fn, } } - pub fn render_nodes<F>(&self, nodes: &Vec<Node>, render_id: f64, render_fn: F) + pub fn render_all_nodes<G>(&self, nodes: &Vec<Node>, render_id: f64, render_fn: G) where - F: Copy + Fn(&Node, &Node), + G: Copy + Fn(&Node, &Node), { info!("Rendering {} nodes", nodes.len()); for n in nodes.iter() { @@ -129,16 +149,7 @@ impl SpaceColonization { } } - pub fn grow<'a>(&mut self, mut nodes: &'a mut Vec<Node>) { - // TODO - // [x] Find a clean API that will be stable across refactoring - // [ ] Write the test against this api including performance - // [x] Find a way to make a compile-time safe datastructure that will ensure that - // - I can store my attractors and their state (remove them or update them when dead) - // - I can store my nodes and their state - // - I can efficiently render my nodes on a canvas - // - I use as little memory as possible - // - I can update my nodes + pub fn grow<'b>(&mut self, mut nodes: &'b mut Vec<Node>) { info!("Growing nodes {:?}", nodes); self.grow_nodes(&mut nodes) } @@ -211,14 +222,15 @@ impl SpaceColonization { (**a).dead = true; } }); + (self.render_fn)(&**node, &new_node); (**node).children.push(new_node); } } }); } - fn build_attractor_to_closest_node<'a>( - &'a mut self, + fn build_attractor_to_closest_node<'b>( + &'b mut self, mut attractor_to_closest_node: &mut HashMap<*mut Attractor, Attraction>, n: &mut Node, ) { @@ -246,7 +258,6 @@ impl SpaceColonization { attractor_to_closest_node.insert(a.0, Attraction::new(n, a.1)); } } - } fn find_attractors_in_range(&mut self, n: &Node) -> Vec<(*mut Attractor, f64)> { @@ -267,13 +278,15 @@ mod test { use super::*; - fn assert_vertices( - sc: &SpaceColonization, - nodes: &Vec<Node>, + fn assert_vertices<'a, F>( + sc: &SpaceColonization<F>, + nodes: &'a Vec<Node>, mut expected_nodes: Vec<(Point, Point)>, - ) { + ) where + F: Copy + Fn(&Node, &Node), + { let rendered_nodes = RefCell::new(Vec::new()); - sc.render_nodes(&nodes, 0.0, |n1, n2| { + sc.render_all_nodes(&nodes, 0.0, |n1: &Node, n2: &Node| { rendered_nodes.borrow_mut().push((n1.position, n2.position)); }); let sort_points = |line1: &(Point, Point), line2: &(Point, Point)| { @@ -298,7 +311,7 @@ mod test { let mut attractors = Vec::new(); attractors.push(Attractor::new(Point::new((10, 0)))); - let mut sc = SpaceColonization::new_for_tests(100, 100, attractors); + let mut sc = SpaceColonization::new_for_tests(100, 100, attractors, |_, _|{}); assert_eq!(sc.attractors.len(), 1); assert!(sc.attractors.iter().find(|a| a.dead == true).is_none()); @@ -344,7 +357,7 @@ mod test { dead: true, }); - let mut sc = SpaceColonization::new_for_tests(100, 100, attractors); + let mut sc = SpaceColonization::new_for_tests(100, 100, attractors, |_, _|{}); assert_eq!(sc.attractors.len(), 1); assert!(sc.attractors.iter().find(|a| a.dead == true).is_some()); From 996f83e92a62cff027db74a55974bf27273d0109 Mon Sep 17 00:00:00 2001 From: jeangab <jg@nationtech.io> Date: Mon, 14 Aug 2023 10:05:46 -0400 Subject: [PATCH 08/11] wip: Spacial index coming along pretty well, some tests and documentation left to write and should be good to go --- src/space_colonization/mod.rs | 1 + src/space_colonization/spacial_index.rs | 110 ++++++++++++++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 src/space_colonization/spacial_index.rs diff --git a/src/space_colonization/mod.rs b/src/space_colonization/mod.rs index 2d6669e..85b6528 100644 --- a/src/space_colonization/mod.rs +++ b/src/space_colonization/mod.rs @@ -5,6 +5,7 @@ pub use point::*; mod space_colonization; pub use space_colonization::*; mod math; +mod spacial_index; #[wasm_bindgen] extern "C" { diff --git a/src/space_colonization/spacial_index.rs b/src/space_colonization/spacial_index.rs new file mode 100644 index 0000000..d5158b0 --- /dev/null +++ b/src/space_colonization/spacial_index.rs @@ -0,0 +1,110 @@ +use super::Point; + +#[derive(Debug)] +struct SpatialIndex<T> { + elements: Vec<Vec<T>>, + number_cells_x: i32, + cell_size: i32, +} + +impl<T> SpatialIndex<T> { + pub fn new(max_point: Point, cell_size: i32) -> SpatialIndex<T> { + // Here we add 1 to number cells x and y to handle the right and bottom edges where + // x = max_point.x or y = max_point.y + // For example, with max_point of (100,100) + // the point 100,100 is valid but 100/10 = 10, which is out of bounds of a zero based + // array of length 10. So we add 1 to the length and 10 is a valid index in a zero based + // array of length 11 + let number_cells_x = (max_point.x / cell_size) + 1; + let number_cells = number_cells_x * ((max_point.y / cell_size) + 1); + let mut elements = Vec::with_capacity(number_cells as usize); + for _ in 0..number_cells { + elements.push(Vec::new()); + } + SpatialIndex { + elements, + cell_size, + number_cells_x, + } + } + + /// Adds an element in the cell of point + /// + /// panics if the point is outside of + pub fn add(&mut self, point: &Point, element: T) { + let element_index = self.get_index_from_position(point); + dbg!(element_index); + self.elements + .get_mut(element_index as usize) + .unwrap() + .push(element); + } + + pub fn get_surrounding_elements<'a>(&'a self, point: &Point) -> Vec<&'a Vec<T>> { + let element_index = self.get_index_from_position(point); + dbg!(element_index); + vec![&self.elements[element_index]] + } + + fn get_index_from_position(&self, point: &Point) -> usize { + ((point.x / self.cell_size) + ((point.y / self.cell_size) * self.number_cells_x)) as usize + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn when_no_element_surrounding_nodes_returns_empty_vec() { + let index: SpatialIndex<usize> = SpatialIndex::new(Point::new((100, 100)), 10); + assert_eq!( + index.get_surrounding_elements(&Point::new((0, 0))), + vec![&Vec::<usize>::new()] + ); + } + + #[test] + fn added_point_is_surrounding_itself() { + let mut index: SpatialIndex<usize> = SpatialIndex::new(Point::new((100, 100)), 10); + index.add(&Point::new((50, 50)), 132); + assert_eq!( + index.get_surrounding_elements(&Point::new((50, 50))), + vec![&vec![132]] + ); + } + + #[test] + fn adding_point_outside_grid_panics() { + todo!(); + } + + #[test] + fn point_on_top_edge_is_close_to_first_cell() { + todo!(); + } + + #[test] + fn point_on_bottom_edge_is_close_to_first_cell() { + todo!(); + } + + #[test] + fn point_on_right_edge_is_close_to_first_cell() { + todo!(); + } + #[test] + fn point_on_left_edge_is_close_to_first_cell() { + todo!(); + } + + #[test] + fn when_elements_too_far_surrounding_is_empty() { + let mut index: SpatialIndex<usize> = SpatialIndex::new(Point::new((100, 100)), 10); + index.add(&Point::new((0, 0)), 132); + assert_eq!( + index.get_surrounding_elements(&Point::new((99, 99))), + vec![&Vec::<usize>::new()] + ); + } +} From 5d6ab1fa71f7d68a4a436b9e1231f0ea2470795f Mon Sep 17 00:00:00 2001 From: jeangab <jg@nationtech.io> Date: Mon, 14 Aug 2023 23:43:40 -0400 Subject: [PATCH 09/11] feat(spacial_indec): Seems to be working nicely at this point, next step use it and see how fast we got --- src/space_colonization/spacial_index.rs | 150 +++++++++++++++++++++--- 1 file changed, 133 insertions(+), 17 deletions(-) diff --git a/src/space_colonization/spacial_index.rs b/src/space_colonization/spacial_index.rs index d5158b0..f833ae5 100644 --- a/src/space_colonization/spacial_index.rs +++ b/src/space_colonization/spacial_index.rs @@ -3,11 +3,18 @@ use super::Point; #[derive(Debug)] struct SpatialIndex<T> { elements: Vec<Vec<T>>, + /// The number of cells between a cell and the cell right below it. + /// + /// For a table of 100x100 with cell_size = 10, number_cells_x is 11 (100/10+1) number_cells_x: i32, cell_size: i32, + max_point: Point, } -impl<T> SpatialIndex<T> { +impl<T> SpatialIndex<T> +where + T: std::fmt::Debug, +{ pub fn new(max_point: Point, cell_size: i32) -> SpatialIndex<T> { // Here we add 1 to number cells x and y to handle the right and bottom edges where // x = max_point.x or y = max_point.y @@ -25,30 +32,84 @@ impl<T> SpatialIndex<T> { elements, cell_size, number_cells_x, + max_point, } } /// Adds an element in the cell of point /// - /// panics if the point is outside of + /// panics if the point is outside of the grid pub fn add(&mut self, point: &Point, element: T) { let element_index = self.get_index_from_position(point); - dbg!(element_index); self.elements .get_mut(element_index as usize) .unwrap() .push(element); } - pub fn get_surrounding_elements<'a>(&'a self, point: &Point) -> Vec<&'a Vec<T>> { - let element_index = self.get_index_from_position(point); - dbg!(element_index); - vec![&self.elements[element_index]] + pub fn get_surrounding_elements<'a>(&'a self, point: &Point) -> Vec<&'a T> { + let surrounding_indices: Vec<usize> = self.get_surrounding_indices(point); + let mut surrounding_elements = Vec::new(); + dbg!(&surrounding_indices); + for i in surrounding_indices { + surrounding_elements.extend(self.elements.get(i).unwrap().iter()); + } + dbg!(&self.elements[115]); + dbg!(&surrounding_elements); + dbg!(&self.elements.len()); + surrounding_elements } fn get_index_from_position(&self, point: &Point) -> usize { ((point.x / self.cell_size) + ((point.y / self.cell_size) * self.number_cells_x)) as usize } + + fn get_surrounding_indices(&self, point: &Point) -> Vec<usize> { + let element_index = self.get_index_from_position(point); + let mut indices = Vec::from([element_index]); + let row_offset = self.number_cells_x as usize; + + // top row + if point.y >= self.cell_size { + // top left + if point.x >= self.cell_size { + indices.push(element_index - row_offset - 1); + } + // top middle + indices.push(element_index - row_offset); + // top right + if point.x < self.max_point.x { + indices.push(element_index - row_offset + 1); + } + } + + // middle left + if point.x >= self.cell_size { + indices.push(element_index - 1); + } + // middle middle can be skipped, already added + + // middle right + if point.x < self.max_point.x { + indices.push(element_index + 1); + } + + if point.y < self.max_point.y { + // bottom left + if point.x >= self.cell_size { + indices.push(element_index + row_offset - 1); + } + + // bottom middle + indices.push(element_index + row_offset); + // bottom right + if point.x < self.max_point.x { + indices.push(element_index + row_offset + 1); + } + } + + indices + } } #[cfg(test)] @@ -60,7 +121,7 @@ mod test { let index: SpatialIndex<usize> = SpatialIndex::new(Point::new((100, 100)), 10); assert_eq!( index.get_surrounding_elements(&Point::new((0, 0))), - vec![&Vec::<usize>::new()] + Vec::<&usize>::new() ); } @@ -70,32 +131,87 @@ mod test { index.add(&Point::new((50, 50)), 132); assert_eq!( index.get_surrounding_elements(&Point::new((50, 50))), - vec![&vec![132]] + vec![&132] ); } #[test] - fn adding_point_outside_grid_panics() { - todo!(); + fn multiple_points_in_every_surrounding_cell() { + let mut index: SpatialIndex<usize> = SpatialIndex::new(Point::new((100, 100)), 10); + index.add(&Point::new((40, 40)), 4040); + index.add(&Point::new((45, 45)), 4040); + index.add(&Point::new((50, 40)), 5040); + index.add(&Point::new((60, 40)), 6040); + index.add(&Point::new((40, 50)), 4050); + index.add(&Point::new((50, 50)), 5050); + index.add(&Point::new((60, 50)), 6050); + index.add(&Point::new((50, 50)), 5050); + index.add(&Point::new((51, 51)), 5151); + index.add(&Point::new((60, 60)), 6060); + index.add(&Point::new((40, 60)), 4060); + index.add(&Point::new((50, 60)), 5060); + index.add(&Point::new((60, 60)), 6060); + assert_eq!( + index.get_surrounding_elements(&Point::new((50, 50))).sort(), + vec![ + &4040, &4545, &5040, &6040, &4050, &5050, &6050, &5050, &5151, &6060, &4060, &5060, &6060, + ].sort() + ); } #[test] fn point_on_top_edge_is_close_to_first_cell() { - todo!(); + let mut index: SpatialIndex<usize> = SpatialIndex::new(Point::new((100, 100)), 10); + index.add(&Point::new((50, 0)), 132); + assert_eq!( + index.get_surrounding_elements(&Point::new((50, 9))), + vec![&132] + ); + assert_eq!( + index.get_surrounding_elements(&Point::new((50, 0))), + vec![&132] + ); } #[test] - fn point_on_bottom_edge_is_close_to_first_cell() { - todo!(); + fn point_on_bottom_edge_is_close_to_bottom_cell() { + let mut index: SpatialIndex<usize> = SpatialIndex::new(Point::new((100, 100)), 10); + index.add(&Point::new((50, 100)), 132); + assert_eq!( + index.get_surrounding_elements(&Point::new((50, 95))), + vec![&132] + ); + assert_eq!( + index.get_surrounding_elements(&Point::new((50, 100))), + vec![&132] + ); } #[test] fn point_on_right_edge_is_close_to_first_cell() { - todo!(); + let mut index: SpatialIndex<usize> = SpatialIndex::new(Point::new((100, 100)), 10); + index.add(&Point::new((100, 50)), 132); + assert_eq!( + index.get_surrounding_elements(&Point::new((95, 50))), + vec![&132] + ); + assert_eq!( + index.get_surrounding_elements(&Point::new((100, 50))), + vec![&132] + ); } #[test] fn point_on_left_edge_is_close_to_first_cell() { - todo!(); + let mut index: SpatialIndex<usize> = SpatialIndex::new(Point::new((100, 100)), 10); + index.add(&Point::new((0, 50)), 132); + assert_eq!( + index.get_surrounding_elements(&Point::new((9, 50))), + vec![&132] + ); + assert_eq!( + index.get_surrounding_elements(&Point::new((0, 50))), + vec![&132] + ); } #[test] @@ -104,7 +220,7 @@ mod test { index.add(&Point::new((0, 0)), 132); assert_eq!( index.get_surrounding_elements(&Point::new((99, 99))), - vec![&Vec::<usize>::new()] + Vec::<&usize>::new() ); } } From 63c13e173981237bd217e04462e5e8ac339dbff9 Mon Sep 17 00:00:00 2001 From: jeangab <jg@nationtech.io> Date: Tue, 15 Aug 2023 15:24:55 -0400 Subject: [PATCH 10/11] chore: run cargo fmt --- src/app.rs | 9 +- src/components/background.rs | 6 +- src/components/mod.rs | 8 +- src/lib.rs | 2 +- src/routes/blog/page.rs | 2 +- src/routes/mod.rs | 4 +- src/routes/whymdc/components.rs | 8 +- src/routes/whymdc/page.rs | 186 +++++++++---------- src/space_colonization/point.rs | 148 ++++++--------- src/space_colonization/space_colonization.rs | 4 +- src/space_colonization/spacial_index.rs | 6 +- 11 files changed, 176 insertions(+), 207 deletions(-) diff --git a/src/app.rs b/src/app.rs index 5a494ca..be1999b 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,9 +1,9 @@ -use crate::components::BackgroundProps; use crate::components::Background; -use crate::routes::whymdc::*; -use crate::routes::home::*; -use crate::routes::empty::*; +use crate::components::BackgroundProps; use crate::routes::blog::*; +use crate::routes::empty::*; +use crate::routes::home::*; +use crate::routes::whymdc::*; use leptos::*; use leptos_meta::*; use leptos_router::*; @@ -44,4 +44,3 @@ pub fn App(cx: Scope) -> impl IntoView { </Router> } } - diff --git a/src/components/background.rs b/src/components/background.rs index 64923ed..3c2e41c 100644 --- a/src/components/background.rs +++ b/src/components/background.rs @@ -40,7 +40,11 @@ pub fn Background(cx: Scope, class: &'static str) -> impl IntoView { context_to_render.move_to(n.position.x.into(), n.position.y.into()); context_to_render.line_to(child.position.x.into(), child.position.y.into()); }; - let mut sc = SpaceColonization::new(width.try_into().unwrap(), height.try_into().unwrap(), render_node_fn); + let mut sc = SpaceColonization::new( + width.try_into().unwrap(), + height.try_into().unwrap(), + render_node_fn, + ); let nodes = Rc::new(RefCell::new(Vec::new())); nodes.borrow_mut().push(Node::new(Point::new(( (window_width / 3) as i32, diff --git a/src/components/mod.rs b/src/components/mod.rs index d9ed078..0909c65 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -1,6 +1,6 @@ -mod codeblock; -mod code; mod background; -pub use codeblock::*; -pub use code::*; +mod code; +mod codeblock; pub use background::*; +pub use code::*; +pub use codeblock::*; diff --git a/src/lib.rs b/src/lib.rs index 716860b..4e330e5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,7 @@ -mod space_colonization; pub mod app; mod components; mod routes; +mod space_colonization; use cfg_if::cfg_if; cfg_if! { diff --git a/src/routes/blog/page.rs b/src/routes/blog/page.rs index 125bd47..d83074b 100644 --- a/src/routes/blog/page.rs +++ b/src/routes/blog/page.rs @@ -1,6 +1,6 @@ +use crate::components::*; use leptos::*; use leptos_meta::*; -use crate::components::*; #[component] pub fn Blog(cx: Scope) -> impl IntoView { diff --git a/src/routes/mod.rs b/src/routes/mod.rs index 22d4b35..e0a4fc8 100644 --- a/src/routes/mod.rs +++ b/src/routes/mod.rs @@ -1,4 +1,4 @@ -pub mod whymdc; -pub mod home; pub mod blog; pub mod empty; +pub mod home; +pub mod whymdc; diff --git a/src/routes/whymdc/components.rs b/src/routes/whymdc/components.rs index 4f80ef4..69ab382 100644 --- a/src/routes/whymdc/components.rs +++ b/src/routes/whymdc/components.rs @@ -3,7 +3,7 @@ use leptos::*; #[component] pub fn Subtitle(cx: Scope, class: &'static str, children: Children) -> impl IntoView { let class = format!("text-3xl font-bold text-white {}", class); - view! { cx, + view! { cx, <h3 class={class}>{children(cx)}</h3> } } @@ -15,7 +15,7 @@ pub fn SectionTitle(cx: Scope, dark: bool, children: Children) -> impl IntoView textColorClass = "text-white"; } let class = format!("text-5xl font-bold text-center {}", textColorClass); - view! { cx, + view! { cx, <h2 class={class}>{children(cx)}</h2> } } @@ -27,9 +27,7 @@ pub fn SubsectionTitle(cx: Scope, dark: bool, children: Children) -> impl IntoVi textColorClass = "text-white"; } let class = format!("text-3xl font-bold {}", textColorClass); - view! { cx, + view! { cx, <h5 class={class}>{children(cx)}</h5> } } - - diff --git a/src/routes/whymdc/page.rs b/src/routes/whymdc/page.rs index 0fe1c3e..c5de887 100644 --- a/src/routes/whymdc/page.rs +++ b/src/routes/whymdc/page.rs @@ -5,7 +5,7 @@ use leptos::*; pub fn WhyMicroDatacenters(cx: Scope) -> impl IntoView { view! { cx, <div class="max-w-[1600px] mx-auto"> - + <div class="flex flex-col min-h-[700px] p-28 bg-cover bg-[url('/img/bg-page1.png')]"> <h1 class="text-orange-400 text-7xl font-extrabold mb-14"> "Micro centres de données" @@ -17,14 +17,14 @@ pub fn WhyMicroDatacenters(cx: Scope) -> impl IntoView { </Subtitle> <img src="/img/NationTech-logo.png" class="mx-auto opacity-50 w-1/4"/> </div> - + <div class="flex-col p-8"> <div class="w-full mx-auto mb-4 border-t-4 border-b-4 border-orange-400 p-4"> <SectionTitle dark=false> "Énergie: le nerf de la guerre" - </SectionTitle> + </SectionTitle> </div> - <div class="mr-72 ml-72"> + <div class="mr-72 ml-72"> <p class="text-justify mb-10 mt-8"> "Tous les systèmes économiques sont basés sur deux variables fondamentales: le temps et l’énergie. Depuis des millénaires l’or est dispendieux. Parce qu’il requiert beaucoup de temps et d’énergie à trouver. Depuis toujours l’eau a une valeur différente à différents endroits de la planète et moments de l’année, en fonction du temps et de l’énergie requis pour la trouver. D’ailleurs, l’énergie est souvent représentée comme fonction du temps. L’unité d’énergie choisie par le Système International, le Joule, s’exprime en Kilogramme X Mètre2 X Seconde2. " </p> @@ -32,14 +32,14 @@ pub fn WhyMicroDatacenters(cx: Scope) -> impl IntoView { "Il convient donc de considérer l’énergie comme fondement principal des différents systèmes économiques. Ce livre blanc vise à étudier les caractéristiques économiques selon différentes métriques naturelles, dont l’énergie est la plus importante, des différentes technologies de déploiement de centres de données. Cette analyse vise plus particulièrement à comparer l’efficacité énergétique, et donc économique, des déploiements de centres de données à très petite et très grande échelle." </p> <p class="text-right font-bold"> - "L’impact global sera calculé en fonction des 5 métriques présentées ci-dessous." + "L’impact global sera calculé en fonction des 5 métriques présentées ci-dessous." </p> </div> </div> - <div class="flex bg-zinc-200 h-[450px] max-[1150px]:h-fit max-[1150px]:flex-col flex-row justify-center items-center"> + <div class="flex bg-zinc-200 h-[450px] max-[1150px]:h-fit max-[1150px]:flex-col flex-row justify-center items-center"> <div class="p-4 mt-8 mb-8 transform min-[1550px]:p-10 max-[1550px]:p-6 max-[1415px]:scale-75 max-[1340px]:p-0 max-[1150px]:scale-100 max-[1150px]:p-8"> - <img src="/img/electricity-icon.png" class="mx-auto"/> + <img src="/img/electricity-icon.png" class="mx-auto"/> <div class="flex justify-center items-center"> <h3 class="p-4 text-blue-950 text-5xl font-semibold"> "1" @@ -66,7 +66,7 @@ pub fn WhyMicroDatacenters(cx: Scope) -> impl IntoView { <h3 class="p-4 text-blue-950 text-5xl font-semibold"> "3" </h3> - <h4 class="font-Lato w-48 p-4 text-blue-950 text-xl font-medium my-auto"> + <h4 class="font-Lato w-48 p-4 text-blue-950 text-xl font-medium my-auto"> "Impact environnemental" </h4> </div> @@ -77,7 +77,7 @@ pub fn WhyMicroDatacenters(cx: Scope) -> impl IntoView { <h3 class="p-4 text-blue-950 text-5xl font-semibold"> "4" </h3> - <h4 class="font-Lato w-48 p-4 text-blue-950 text-xl font-medium my-auto"> + <h4 class="font-Lato w-48 p-4 text-blue-950 text-xl font-medium my-auto"> "Impact économique" </h4> </div> @@ -95,8 +95,8 @@ pub fn WhyMicroDatacenters(cx: Scope) -> impl IntoView { </div> </div> - <div class="justify-center items-center flex h-[250px] bg-cover bg-center bg-opacity-75 bg-[url('/img/server-wires-page3.png')]"> - <div class="p-16 w-full"> + <div class="justify-center items-center flex h-[250px] bg-cover bg-center bg-opacity-75 bg-[url('/img/server-wires-page3.png')]"> + <div class="p-16 w-full"> <div class="w-full h-fit border-t-4 border-b-4 border-orange-400 p-4"> <SectionTitle dark=true> "Qu'est-ce qu'un centre de données" @@ -106,27 +106,27 @@ pub fn WhyMicroDatacenters(cx: Scope) -> impl IntoView { </div> <div class="flex flex-col"> <div class="p-8 w-fit h-fit mr-72 ml-72"> - <div class="w-fit pt-4 pb-4 border-r-8 border-indigo-500 pr-2"> + <div class="w-fit pt-4 pb-4 border-r-8 border-indigo-500 pr-2"> <div class="flex-col"> <div class="flex justify-end pb-4"> <SubsectionTitle dark=true> "Micro centres de données (MCD)" </SubsectionTitle> </div> - <p class="text-right mr-2 text-white"> + <p class="text-right mr-2 text-white"> "Un MCD est une unité de serveurs de petite taille pouvant être installée dans n’importe quel immeuble, tant les maisons unifamiliales que les gratte-ciels ou les usines. Sa taille est adaptée aux besoins énergétiques de l’immeuble qui l’abrite. Les rejets énergétiques, le plus souvent sous forme de chaleur, sont réutilisés au maximum dans l’immeuble pour le chauffer. Ils peuvent également être utilisée pour chauffer l’eau, ou même regénérer de l’électricité dans certains cas. Ce type de déploiement réduit également les besoins de climatisation du centre de données puisque la chaleur est transférée à d’autres usages. L’énergie totale consommée par le centre de données est donc déjà réduite." </p> </div> </div> </div> <div class="p-8 w-fit h-fit pb-24 mr-72 ml-72"> - <div class="w-fit pt-4 pb-4 border-l-8 border-indigo-500 pl-2"> + <div class="w-fit pt-4 pb-4 border-l-8 border-indigo-500 pl-2"> <div class="flex-col"> <div class="flex justify-start pb-4"> <SubsectionTitle dark=true> "Centres de données grande échelle (CDGE)" </SubsectionTitle> - </div> + </div> <div class="flex justify-start pb-4 text-white"> "Un CDGE est une unité constituée de milliers, voire de millions de serveurs centralisés sous un même toît. De tels serveurs sont généralement contenus dans d’énormes bâtiments exclusivement dédiés à l’hébergement de serveurs, ce qui requiert des systèmes de refroidissement énergivores." </div> @@ -189,7 +189,7 @@ pub fn WhyMicroDatacenters(cx: Scope) -> impl IntoView { <div class="flex flex-col justify-center"> </div> - + <div class="flex-col p-8"> <div class="mx-auto h-fit w-full border-t-4 border-b-4 border-orange-400 p-4"> <SectionTitle dark=false> @@ -199,7 +199,7 @@ pub fn WhyMicroDatacenters(cx: Scope) -> impl IntoView { <div class="flex flex-row max-[1060px]:flex-col max-[1060px]:space-y-20 justify-center mt-16"> <div class="flex flex-col justify-center pl-40 pr-40 max-[1460px]:pl-16 max-[1460px]:pr-16"> <img src="/img/electricity-icon.png" class="transform mx-auto"/> - <h4 class="font-Lato mx-auto text-center w-64 p-4 text-blue-950 text-3xl font-bold"> + <h4 class="font-Lato mx-auto text-center w-64 p-4 text-blue-950 text-3xl font-bold"> "Consommation d'énergie démesurée" </h4> </div> @@ -219,26 +219,26 @@ pub fn WhyMicroDatacenters(cx: Scope) -> impl IntoView { <div class="flex flex-row max-[1060px]:flex-col min-[1060px]:pt-16 max-[1060px]:space-y-20 max-[1060px]:mt-20 justify-center"> <div class="flex flex-col justify-center pl-40 pr-40 max-[1460px]:pl-16 max-[1460px]:pr-16"> <img src="/img/coin-icon.png" class="transform mx-auto"/> - <h4 class="font-Lato mx-auto text-center w-64 p-4 text-blue-950 text-3xl font-bold"> + <h4 class="font-Lato mx-auto text-center w-64 p-4 text-blue-950 text-3xl font-bold"> "Coûts exorbitants" </h4> </div> <div class="flex flex-col justify-center pl-40 pr-40 max-[1460px]:pl-16 max-[1460px]:pr-16"> <img src="/img/group-icon.png" class="transform mx-auto"/> - <h4 class="font-Lato mx-auto text-center w-64 p-4 text-blue-950 text-3xl font-bold"> + <h4 class="font-Lato mx-auto text-center w-64 p-4 text-blue-950 text-3xl font-bold"> "Impact social négatif" </h4> </div> - </div> + </div> </div> - + <div class="flex flex-col bg-zinc-200 justify-center p-8"> <div class="mx-auto h-fit w-full border-t-4 border-b-4 border-orange-400 p-8"> <SectionTitle dark=false> "Consommation d'énergie démesurée" </SectionTitle> </div> - <div class="flex flex-col justify-center pt-4 pb-4 pl-2 mt-16 mr-72 ml-72 border-l-8 border-blue-400"> + <div class="flex flex-col justify-center pt-4 pb-4 pl-2 mt-16 mr-72 ml-72 border-l-8 border-blue-400"> <p class="text-justify p-4 mb=32"> "On estime qu’en 2030, les technologies de l’information et de la communication, qui sont principalement basées sur l’utilisation de serveurs informatiques, pourraient dans le pire des cas consommer 51% l’électricité mondiale et, dans le meilleur des cas, 8% de l’électricité mondiale (Andrae & Edler, 2015; Jones, 2018). On estime que 50% de l’électricité consommée par les CDGE sert au refroidissement des serveurs (The Impact of Data Centers on The Environment, 2022). Cette consommation d’énergie est non seulement excessive, mais aussi hautement inefficiente. À titre illustratif, les résultats d’une simulation réalisée dans le cadre d’une étude chinoise réalisée en 2018 indiquaient que la charge cumulative annuelle de refroidissement d’un CD était beaucoup plus élevée que la charge cumulative annuelle de chaleur (Yu et al., 2019, p. 154). Le potentiel de réutilisation de la chaleur est donc énorme, de même que le gaspillage énergétique actuel." </p> @@ -251,7 +251,7 @@ pub fn WhyMicroDatacenters(cx: Scope) -> impl IntoView { </div> <div class="justify-center items-center flex h-[250px] bg-cover bg-center bg-opacity-90 bg-[url('/img/bg-water.jpg')]"> - <div class="p-16 w-full"> + <div class="p-16 w-full"> <div class="h-fit w-full border-t-4 border-b-4 border-orange-400 p-8"> <SectionTitle dark=true> "Consommation d'eau démesurée" @@ -269,10 +269,10 @@ pub fn WhyMicroDatacenters(cx: Scope) -> impl IntoView { <div class="flex flex-col bg-zinc-200 justify-center p-8"> <div class="mx-auto h-fit w-full border-t-4 border-b-4 border-orange-400 p-8"> - + <SectionTitle dark=false> "Impact environnemental majeur" - </SectionTitle> + </SectionTitle> </div> <p class="text-justify mb-12 mt-8 ml-72 mr-72"> "Quant aux émissions de gaz à effet de serre (GES) des géants du web, le tableau suivant résume la situation en 2021 pour Amazon, Microsoft, Alphabet et Meta. À titre indicatif, l’empreinte carbone per capita aux États-Unis est d’environ 16 tonnes métriques d’équivalent CO2 (tCO2e) et l’empreinte per capita à l’échelle planétaire est d’environ 4 tCO2e (What Is Your Carbon Footprint? | Carbon Footprint Calculator, n.d.)" @@ -289,38 +289,38 @@ pub fn WhyMicroDatacenters(cx: Scope) -> impl IntoView { "d'Amazon, Microsoft, Alphabet et Meta" </h4> <div class="bg-zinc-200 grid grid-cols-4 grid-rows-3 gap-y-4 ml-[450px] mr-[450px]"> - <h4 class="flex fit-content items-center justify-center w-fit max-h-[68px] rounded-lg font-Lato bg-white mx-auto text-center p-4 text-blue-950 text-xl font-bold"> + <h4 class="flex fit-content items-center justify-center w-fit max-h-[68px] rounded-lg font-Lato bg-white mx-auto text-center p-4 text-blue-950 text-xl font-bold"> "Catégories d'émissions" </h4> - <div class="flex fit-content border-b-4 border-r-2 border-black pb-4"> - <h4 class="flex items-center justify-center w-[142px] h-[68px] rounded-lg font-Lato bg-white mx-auto text-center p-4 text-blue-950 text-2xl font-bold"> + <div class="flex fit-content border-b-4 border-r-2 border-black pb-4"> + <h4 class="flex items-center justify-center w-[142px] h-[68px] rounded-lg font-Lato bg-white mx-auto text-center p-4 text-blue-950 text-2xl font-bold"> "Scope 1" </h4> </div> <div class="flex fit-content border-b-4 border-r-2 border-black pb-4"> - <h4 class="flex items-center justify-center w-[142px] h-[68px] rounded-lg font-Lato bg-white mx-auto text-center p-4 text-blue-950 text-2xl font-bold"> + <h4 class="flex items-center justify-center w-[142px] h-[68px] rounded-lg font-Lato bg-white mx-auto text-center p-4 text-blue-950 text-2xl font-bold"> "Scope 2" </h4> </div> <div class="flexfit-content border-b-4 border-black pb-4"> - <h4 class="flex items-center justify-center w-[142px] h-[68px] rounded-lg font-Lato bg-white mx-auto text-center p-4 text-blue-950 text-2xl font-bold"> + <h4 class="flex items-center justify-center w-[142px] h-[68px] rounded-lg font-Lato bg-white mx-auto text-center p-4 text-blue-950 text-2xl font-bold"> "Scope 3" </h4> </div> - <h4 class="flex fit-content items-center justify-center max-h-[68px] rounded-lg font-Lato bg-white mx-auto text-center w-fit p-4 text-blue-950 text-xl font-bold -translate-y-1"> + <h4 class="flex fit-content items-center justify-center max-h-[68px] rounded-lg font-Lato bg-white mx-auto text-center w-fit p-4 text-blue-950 text-xl font-bold -translate-y-1"> "Quantité (tCO2e)" </h4> <div class="flex fit-content border-r-2 pt-4 border-black -translate-y-5"> - <h4 class="flex items-center justify-center w-[142px] h-[68px] rounded-lg font-Lato bg-white mx-auto text-center p-4 text-blue-950 text-xl font-bold"> + <h4 class="flex items-center justify-center w-[142px] h-[68px] rounded-lg font-Lato bg-white mx-auto text-center p-4 text-blue-950 text-xl font-bold"> "9 837 398" </h4> </div> <div class="flex fit-content border-r-2 pt-4 border-black -translate-y-5"> - <h4 class="flex items-center justify-center w-[142px] h-[68px] rounded-lg font-Lato bg-white mx-auto text-center p-4 text-blue-950 text-xl font-bold"> + <h4 class="flex items-center justify-center w-[142px] h-[68px] rounded-lg font-Lato bg-white mx-auto text-center p-4 text-blue-950 text-xl font-bold"> "6 347 350" </h4> </div> - <h4 class="flex items-center justify-center w-[142px] h-[68px] rounded-lg font-Lato bg-white mx-auto text-center p-4 text-blue-950 text-xl font-bold"> + <h4 class="flex items-center justify-center w-[142px] h-[68px] rounded-lg font-Lato bg-white mx-auto text-center p-4 text-blue-950 text-xl font-bold"> "74 566 000" </h4> <h4 class="flex items-center justify-center max-h-[68px] rounded-lg font-Lat bg-white mx-auto text-center p-4 text-blue-950 text-xl font-bold max-w-[175px] translate-y-1"> @@ -330,74 +330,74 @@ pub fn WhyMicroDatacenters(cx: Scope) -> impl IntoView { "" </div> <div class="flex fit-content border-t-4 pt-4 border-black -translate-y-3"> - <h4 class="flex items-center justify-center w-[300px] h-[68px] rounded-lg font-Lato bg-white mx-auto text-center p-4 text-blue-950 text-2xl font-bold"> + <h4 class="flex items-center justify-center w-[300px] h-[68px] rounded-lg font-Lato bg-white mx-auto text-center p-4 text-blue-950 text-2xl font-bold"> "90 750 748" </h4> </div> <div class="flex border-t-4 pt-4 border-black -translate-y-3"> - "" + "" </div> </div> </div> - + <div class="flex flex-col justify-center p-8"> - <div class="mx-auto h-fit w-full border-t-4 border-b-4 border-orange-400 p-8"> + <div class="mx-auto h-fit w-full border-t-4 border-b-4 border-orange-400 p-8"> <SectionTitle dark=false> "Coûts exorbitants" </SectionTitle> </div> - <div class="flex flex-col justify-center pt-4 pb-4 pl-2 mt-16 mr-72 ml-72 border-l-8 border-blue-400"> + <div class="flex flex-col justify-center pt-4 pb-4 pl-2 mt-16 mr-72 ml-72 border-l-8 border-blue-400"> <p class="text-justify p-4 mb=32"> "Le coût de construction, d’exploitation et d’entretien d’un CDGE est extrêmement élevé. En effet, le coût de construction oscille entre $7 millions et $12 millions par mégawatt (MW) (Zhang, 2022a). Sachant que les centres de données de Google Cloud Platform (GCP) consomment en moyenne 20 MW, on parle d’un coût de construction entre $140 M et $240 M." </p> </div> - + <div class="flex flex-col justify-center pt-4 pb-4 pl-2 mb-12 mt-16 mr-72 ml-72 border-r-8 border-blue-400"> <p class="text-right p-4 mb=32"> "Or, la consommation électrique d’un CD en MW ne représente pas nécessairement sa capacité de stockage ou de traitement des données. En effet, leur consommation électrique est non seulement liée au fonctionnement des équipements informatiques, mais aussi en grande partie aux besoins de refroidissement et de distribution d'énergie. Cette consommation d’électricité augmente donc rapidement avec la taille des centres de données. " </p> </div> </div> - + <div class="flex flex-col justify-center p-8"> <div class="mx-auto h-fit w-full border-t-4 border-b-4 border-orange-400 p-8"> <SectionTitle dark=true> "Impact social négatif" </SectionTitle> </div> - <p class="text-justify mt-8 text-white ml-72 mr-72"> + <p class="text-justify mt-8 text-white ml-72 mr-72"> "Les quatre problèmes ci-haut identifiés préoccupent de nombreuses personnes. Par exemple, dans les régions désertiques de l’Ouest américain où les big tech s’installent pour l’abondance d’énergie renouvelable, notamment l’énergie solaire, plusieurs communautés sont préoccupées par les quantités astronomiques d’eau consommées par les CDGE (Solon, 2021). En Arizona, où Apple a élu domicile pour un de ses CD, on indique que le niveau du principal réservoir d’eau de la région a atteint de bas niveaux historiques (James, 2021). La mairesse de Mesa, ville où se trouve le CD en question, se confiait à BBC News en 2021: " </p> - <p class="text-right italic mt-8 text-white ml-[450px] mr-[450px]"> + <p class="text-right italic mt-8 text-white ml-[450px] mr-[450px]"> "When it comes to economic development, I don’t think we are fully transparent about the water concerns [...] We want to keep the image that we are a great place to invest and start a business. But we don’t like to talk about the water." </p> <p class="text-right italic text-white ml-[450px] mr-[450px]"> "(Solon, 2021)" </p> - <p class="text-justify mt-8 text-white ml-72 mr-72"> + <p class="text-justify mt-8 text-white ml-72 mr-72"> "Similairement, Microsoft s’est fait reprocher de manquer de transparence quant à son utilisation dans un de ces CD au Pays-Bas. L’entreprise avait indiqué qu’elle utiliserait de 12 M à 20 M de litres d’eau par an. Or, on découvrait qu’elle avait plutôt utilisé 84 M de litres d’eau en 2021, alors que des vagues de chaleur causaient d’importantes pénuries d’eau cette même année. Ce manque de transparence chronique est révélateur d’un profond problème de responsabilité sociale de ces grandes industries." </p> - <p class="text-justify mt-8 text-white ml-72 mr-72"> + <p class="text-justify mt-8 text-white ml-72 mr-72"> "Le manque de transparence touche non seulement la gestion environnementale des projets, mais aussi le fonctionnement desdits CD comme l’illustre le graphique ci-bas." </p> <h4 class="flex justify-center text-center mt-16 font-Lato text-white text-3xl font-extrabold ml-[450px] mr-[450px]"> "Compréhension du public quant à l'utilisation des CD et la gestion de leurs données" </h4> - <div class="flex justify-center items-center p-8"> - <img src="/img/graph-1.png"/> + <div class="flex justify-center items-center p-8"> + <img src="/img/graph-1.png"/> </div> - <p class="text-justify mt-2 text-neutral-400 text-xs ml-72 mr-72"> + <p class="text-justify mt-2 text-neutral-400 text-xs ml-72 mr-72"> "Sources:" </p> - <p class="text-justify mt-2 text-neutral-400 text-xs ml-72 mr-72"> + <p class="text-justify mt-2 text-neutral-400 text-xs ml-72 mr-72"> "https://www.statista.com/statistics/617136/digital-population-worldwide/?fbclid=IwAR0bHpZ0u4JbW1hW2QI5WqJKmFhsmwJBwmviNVnesn-6rNhnQQCkbYrT1OU" </p> - <p class="text-justify mt-2 text-neutral-400 text-xs ml-72 mr-72"> + <p class="text-justify mt-2 text-neutral-400 text-xs ml-72 mr-72"> "https://www.pewresearch.org/internet/2019/11/15/americans-and-privacy-concerned-confused-and-feeling-lack-of-control-over-their-personal-information/?fbcli -d=IwAR3wuxdHW8VE30FMaqZ6Iuj9Cs86bRSvmij1e_zDjM6Bwo4l71n5EKcLxqY" + d=IwAR3wuxdHW8VE30FMaqZ6Iuj9Cs86bRSvmij1e_zDjM6Bwo4l71n5EKcLxqY" </p> </div> - + <div class="flex-col bg-zinc-200 p-8"> <div class="mx-auto h-fit w-full border-t-4 border-b-4 border-orange-400 p-8"> <SectionTitle dark=false> @@ -407,7 +407,7 @@ d=IwAR3wuxdHW8VE30FMaqZ6Iuj9Cs86bRSvmij1e_zDjM6Bwo4l71n5EKcLxqY" <div class="flex flex-row max-[1060px]:flex-col max-[1060px]:space-y-20 justify-center mt-16"> <div class="flex flex-col justify-center pl-40 pr-40 max-[1460px]:pl-16 max-[1460px]:pr-16"> <img src="/img/electricity-icon.png" class="transform mx-auto"/> - <h4 class="font-Lato mx-auto text-center w-64 p-4 text-blue-950 text-3xl font-bold"> + <h4 class="font-Lato mx-auto text-center w-64 p-4 text-blue-950 text-3xl font-bold"> "Consommation d’énergie responsable et durable" </h4> </div> @@ -425,17 +425,17 @@ d=IwAR3wuxdHW8VE30FMaqZ6Iuj9Cs86bRSvmij1e_zDjM6Bwo4l71n5EKcLxqY" <div class="flex flex-row max-[1060px]:flex-col min-[1060px]:pt-16 max-[1060px]:space-y-20 max-[1060px]:mt-20 justify-center"> <div class="flex flex-col justify-center pl-40 pr-40 max-[1460px]:pl-16 max-[1460px]:pr-16"> <img src="/img/coin-icon.png" class="transform mx-auto"/> - <h4 class="font-Lato mx-auto text-center w-64 p-4 text-blue-950 text-3xl font-bold"> + <h4 class="font-Lato mx-auto text-center w-64 p-4 text-blue-950 text-3xl font-bold"> "Faibles coûts" </h4> </div> <div class="flex flex-col justify-center pl-40 pr-40 max-[1460px]:pl-16 max-[1460px]:pr-16"> <img src="/img/group-icon.png" class="transform mx-auto"/> - <h4 class="font-Lato mx-auto text-center w-64 p-4 text-blue-950 text-3xl font-bold"> + <h4 class="font-Lato mx-auto text-center w-64 p-4 text-blue-950 text-3xl font-bold"> "Impact social positif" </h4> </div> - </div> + </div> </div> <div class="justify-center items-center flex h-[250px] bg-cover bg-bottom bg-opacity-75 bg-[url('/img/solar-panel.jpg')]"> @@ -449,25 +449,25 @@ d=IwAR3wuxdHW8VE30FMaqZ6Iuj9Cs86bRSvmij1e_zDjM6Bwo4l71n5EKcLxqY" </div> </div> </div> - <div class="flex flex-col justify-center pt-4 pb-4 pl-2 mt-16 mr-72 ml-72 border-l-8 border-blue-400"> + <div class="flex flex-col justify-center pt-4 pb-4 pl-2 mt-16 mr-72 ml-72 border-l-8 border-blue-400"> <p class="text-left p-4 mb=32"> "Les MCD, tels que ceux développés par NationTech, consomment une fraction de l’énergie d’un CDGE. La clé de cette augmentation de l’efficacité énergétique est la réutilisation de la chaleur. En effet, les CDGE refroidissent l’équipement informatique grâce à des systèmes de climatisation énergivores tandis que les MCD extraient la chaleur via un système d’aération ou de refroidissement liquide qui la distribue afin de combler les besoins en chauffage d’eau et d’air d’un immeuble donné. Ainsi, l’électricité normalement utilisée afin de faire chauffer une résistance dans un radiateur servira plutôt à faire chauffer des serveurs. Suivant un principe physique de base, les rejets thermiques étant pratiquement identiques." </p> </div> <div class="mt-8 mx-auto max-w-[425px]"> <SectionTitle dark=false> - "Rien ne se perd, Rien ne se crée, Tout se transforme" + "Rien ne se perd, Rien ne se crée, Tout se transforme" </SectionTitle> <p class="mt-2 text-right text-blue-950 font-sm"> "Antoine Lavoisier" </p> </div> - <div class="flex flex-col justify-center pt-4 pb-4 pl-2 mb-16 mt-16 mr-72 ml-72 border-r-8 border-blue-400"> + <div class="flex flex-col justify-center pt-4 pb-4 pl-2 mb-16 mt-16 mr-72 ml-72 border-r-8 border-blue-400"> <p class="text-right p-4 mb=32"> "Deux métriques sont ci-après utilisées afin de comparer l’efficacité énergétique des MCD par rapport à celle des CDGE: le power usage effectiveness (PUE) ainsi que le energy reuse factor (ERF). NationTech a créé une troisième métrique permettant de fusionner les deux première: le global power usage effectiveness (GPUE)." </p> </div> - + <div class="flex-col bg-zinc-200 p-8"> <div class="mx-auto h-fit w-full border-t-4 border-b-4 border-orange-400 p-4"> <SectionTitle dark=false> @@ -490,8 +490,8 @@ d=IwAR3wuxdHW8VE30FMaqZ6Iuj9Cs86bRSvmij1e_zDjM6Bwo4l71n5EKcLxqY" <h4 class="flex justify-center text-center mt-16 font-Lato text-blue-950 text-5xl font-extrabold"> "Power Usage Effectiveness (PUE)" </h4> - <div class="flex justify-center items-center p-8"> - <img src="/img/graph-2.png"/> + <div class="flex justify-center items-center p-8"> + <img src="/img/graph-2.png"/> </div> <p class="justify-center text-right ml-48 mr-48"> "*Voir section sur le GPUE" @@ -521,24 +521,24 @@ d=IwAR3wuxdHW8VE30FMaqZ6Iuj9Cs86bRSvmij1e_zDjM6Bwo4l71n5EKcLxqY" <h4 class="flex justify-center text-center mt-16 font-Lato text-white text-5xl font-extrabold"> "Energy reuse factor (ERF)" </h4> - <div class="flex justify-center items-center p-8"> - <img src="/img/graph-3.png"/> + <div class="flex justify-center items-center p-8"> + <img src="/img/graph-3.png"/> </div> </div> </div> - <div class="flex flex-col justify-center pt-4 pb-4 pl-2 mt-16 mr-72 ml-72 border-l-8 border-blue-400"> + <div class="flex flex-col justify-center pt-4 pb-4 pl-2 mt-16 mr-72 ml-72 border-l-8 border-blue-400"> <p class="text-left p-4 mb=32"> "Les MCD visent à réutiliser la majorité de l’énergie utilisée afin de faire fonctionner le CD. Les rejets thermiques de l’équipement informatiques, soit l’ensemble de l’énergie entrant dans le CD moins l’électricité utilisée pour les ventilateurs et le courant électrique passant dans la fibre optique, est réutilisée afin de chauffer un immeuble. Dans le cas des CDGE, aucune énergie n’est réutilisée. En effet, on refroidit plutôt les installations avec des systèmes de climatisation énergivores ou bien avec de l’eau qui, une fois chaude, donc chargée énergétiquement, est rejetée dans la nature sans être réutilisée." </p> </div> <div class="mb-8"> - <div class="flex flex-col justify-center pt-4 pb-4 pl-2 mt-16 mr-72 ml-72 border-r-8 border-blue-400"> + <div class="flex flex-col justify-center pt-4 pb-4 pl-2 mt-16 mr-72 ml-72 border-r-8 border-blue-400"> <p class="text-right p-4"> "Les géants de l’industrie ont quelques projets sur la table afin de réutiliser la chaleur de leurs serveurs. Cependant, pour le moment, c’est une part infime de leurs CD qui recyclent la chaleur produite. Azure indique pourtant que le potentiel est énorme: selon les estimations de l’entreprise, il serait possible d’atteindre un ERF de 0.69 en hiver et 0.84 en été." </p> </div> </div> - + <div class="flex-col p-8"> <div class="mx-auto h-fit w-full border-t-4 border-b-4 border-orange-400 p-4"> <SectionTitle dark=true> @@ -559,12 +559,12 @@ d=IwAR3wuxdHW8VE30FMaqZ6Iuj9Cs86bRSvmij1e_zDjM6Bwo4l71n5EKcLxqY" "Global Power Usage Effectiveness (GPUE)" </h4> <div class="flex justify-center items-center p-8"> - <img src="/img/graph-4.png"/> + <img src="/img/graph-4.png"/> </div> </div> </div> <div class="mb-8"> - <div class="flex flex-col justify-center pt-4 pb-4 pl-2 mt-16 mr-72 ml-72 border-l-8 border-blue-400"> + <div class="flex flex-col justify-center pt-4 pb-4 pl-2 mt-16 mr-72 ml-72 border-l-8 border-blue-400"> <p class="text-left p-4"> "Meta, Azure, Vantage, Equinix et AWS projettent toutes réutiliser l’énergie de leurs centres de données afin d’atteindre la carboneutralité d’ici 2030. À l’exception de Vantage, elles ont toutes implémenter des projets de réutilisation de la chaleur produite par l’équipement informatique de leurs centres de données. Aucune information n’a été trouvée quant à l’intention de Google d’implémenter de tels projets. Voici un bref résumé de ces initiatives." </p> @@ -575,7 +575,7 @@ d=IwAR3wuxdHW8VE30FMaqZ6Iuj9Cs86bRSvmij1e_zDjM6Bwo4l71n5EKcLxqY" <div class="flex flex-row"> <div class="flex w-1/2 justify-center items-center p-8"> <img src="/img/Facebook-logo.jpg" class="mx-auto mt-8 mb-8 rounded-lg w-1/2"/> - </div> + </div> <div class="flex justify-center center w-1/2 bg-zinc-200"> <div class="my-auto"> <p class="mx-auto mr-32 ml-32 text-justify"> @@ -587,7 +587,7 @@ d=IwAR3wuxdHW8VE30FMaqZ6Iuj9Cs86bRSvmij1e_zDjM6Bwo4l71n5EKcLxqY" <div class="flex flex-row"> <div class="flex w-1/2 justify-center items-center p-8"> <img src="/img/Microsoft-logo.jpg" class="h-[231.23px] mx-auto mt-8 mb-8 rounded-lg w-1/2"/> - </div> + </div> <div class="flex justify-center center w-1/2 bg-zinc-200"> <div class="my-auto"> <p class="mx-auto mr-32 ml-32 text-justify"> @@ -600,8 +600,8 @@ d=IwAR3wuxdHW8VE30FMaqZ6Iuj9Cs86bRSvmij1e_zDjM6Bwo4l71n5EKcLxqY" <div class="flex w-1/2 justify-center items-center p-8"> <div class="flex h-[231.23px] w-[368px] bg-white rounded-lg"> <img src="/img/Vantage-logo.png" class="mx-auto mt-8 mb-8 h-3/4 w-3/4"/> - </div> - </div> + </div> + </div> <div class="flex justify-center center w-1/2 bg-zinc-200"> <div class="my-auto"> <p class="mx-auto mr-32 ml-32 text-justify"> @@ -613,7 +613,7 @@ d=IwAR3wuxdHW8VE30FMaqZ6Iuj9Cs86bRSvmij1e_zDjM6Bwo4l71n5EKcLxqY" <div class="flex flex-row"> <div class="flex w-1/2 justify-center items-center p-8"> <img src="/img/Equinix-logo.jpg" class="h-[231.23px] mx-auto mt-8 mb-8 rounded-lg w-1/2"/> - </div> + </div> <div class="flex justify-center center w-1/2 bg-zinc-200"> <div class="my-auto"> <p class="mx-auto mr-32 ml-32 text-justify"> @@ -625,7 +625,7 @@ d=IwAR3wuxdHW8VE30FMaqZ6Iuj9Cs86bRSvmij1e_zDjM6Bwo4l71n5EKcLxqY" <div class="flex flex-row"> <div class="flex w-1/2 justify-center items-center p-8"> <img src="/img/Amazon-logo.jpg" class="h-[231.23px] mx-auto mt-8 mb-8 rounded-lg w-1/2"/> - </div> + </div> <div class="flex justify-center center w-1/2 bg-zinc-200"> <div class="my-auto"> <p class="mx-auto mr-32 ml-32 text-justify"> @@ -635,20 +635,20 @@ d=IwAR3wuxdHW8VE30FMaqZ6Iuj9Cs86bRSvmij1e_zDjM6Bwo4l71n5EKcLxqY" </div> </div> </div> - + <div class="flex flex-col justify-center p-8"> - <div class="mx-auto h-fit w-full border-t-4 border-b-4 border-orange-400 p-8"> + <div class="mx-auto h-fit w-full border-t-4 border-b-4 border-orange-400 p-8"> <SectionTitle dark=false> "Consommation d'eau responsable et durable" </SectionTitle> </div> - <div class="flex flex-col justify-center pt-4 pb-4 mb-8 pl-2 mt-16 mr-72 ml-72 border-l-8 border-blue-400"> + <div class="flex flex-col justify-center pt-4 pb-4 mb-8 pl-2 mt-16 mr-72 ml-72 border-l-8 border-blue-400"> <p class="text-justify p-4 mb=32"> "Les MCD tels que développés par NationTech ne consomment pas d’eau. En effet, l’entreprise offre deux options afin de distribuer la chaleur dans les immeubles qu’elle chauffe: soit un système de ventilation conventionnel distribuant la chaleur des serveurs grâce à des ventilateurs, soit un système de refroidissement liquide qui absorbe la chaleur produite pour la redistribuer dans l’immeuble." </p> </div> </div> - + <div class="flex-col bg-zinc-200 p-8"> <div class="mx-auto h-fit w-full border-t-4 border-b-4 border-orange-400 p-4"> <SectionTitle dark=false> @@ -664,7 +664,7 @@ d=IwAR3wuxdHW8VE30FMaqZ6Iuj9Cs86bRSvmij1e_zDjM6Bwo4l71n5EKcLxqY" </p> </div> </div> - + <div class="flex-col p-8"> <div class="flex justify-center flex-col ml-72 mr-72"> <p class="justify-center text-justify mt-8"> "La figure suivante présente le WUE moyen des entreprise Meta, Google, Microsoft, Vantage, Equinix et Amazon pour leur CDGE ainsi que le WUE de NationTech dans ses MCD." @@ -677,17 +677,17 @@ d=IwAR3wuxdHW8VE30FMaqZ6Iuj9Cs86bRSvmij1e_zDjM6Bwo4l71n5EKcLxqY" <p class="justify-center text-justify mt-8"> "La figure suivante présente le WUE moyen des entreprise Meta, Google, Microsoft, Vantage, Equinix et Amazon pour leur CDGE ainsi que le WUE de NationTech dans ses MCD." </p> - <h4 class="flex justify-center text-center mt-16 font-Lato text-5xl font-extrabold"> + <h4 class="flex justify-center text-center mt-16 font-Lato text-5xl font-extrabold"> "Water Usage Effectiveness (WUE)" </h4> <div class="flex justify-center items-center p-8"> - <img src="/img/graph-5.png" class="mt-8 mb-8 scale-125"/> + <img src="/img/graph-5.png" class="mt-8 mb-8 scale-125"/> </div> </div> </div> <div class="flex flex-col p-8 "> - <div class="pt-16 w-full"> + <div class="pt-16 w-full"> <div class="h-fit w-full border-t-4 border-b-4 border-orange-400 p-8"> <SectionTitle dark=true> "Impact environnemental nul" @@ -709,7 +709,7 @@ d=IwAR3wuxdHW8VE30FMaqZ6Iuj9Cs86bRSvmij1e_zDjM6Bwo4l71n5EKcLxqY" "Température froide" </p> <div class="mb-4 flex flex-row"> - <div class="flex items-center"> + <div class="flex items-center"> <p class="mr-12 text-left font-extrabold text-4xl text-white"> "1" </p> @@ -719,7 +719,7 @@ d=IwAR3wuxdHW8VE30FMaqZ6Iuj9Cs86bRSvmij1e_zDjM6Bwo4l71n5EKcLxqY" </p> </div> <div class="mb-4 flex flex-row"> - <div class="flex items-center"> + <div class="flex items-center"> <p class="mr-12 text-left font-extrabold text-4xl text-white"> "2" </p> @@ -729,7 +729,7 @@ d=IwAR3wuxdHW8VE30FMaqZ6Iuj9Cs86bRSvmij1e_zDjM6Bwo4l71n5EKcLxqY" </p> </div> <div class="mb-4 flex flex-row"> - <div class="flex items-center"> + <div class="flex items-center"> <p class="mr-12 text-left font-extrabold text-4xl text-white"> "3" </p> @@ -739,7 +739,7 @@ d=IwAR3wuxdHW8VE30FMaqZ6Iuj9Cs86bRSvmij1e_zDjM6Bwo4l71n5EKcLxqY" </p> </div> <div class="flex flex-row"> - <div class="flex items-center"> + <div class="flex items-center"> <p class="mr-12 text-left font-extrabold text-4xl text-white"> "4" </p> @@ -747,9 +747,9 @@ d=IwAR3wuxdHW8VE30FMaqZ6Iuj9Cs86bRSvmij1e_zDjM6Bwo4l71n5EKcLxqY" <p class="text-justify text-white"> "Cet air est utilisé pour chauffer la maison afin d’atteindre la température cible." </p> - </div> + </div> </div> - + </div> <div class="flex flex-row p-16"> <img src="/img/house-2.png" class="mr-4"/> @@ -758,7 +758,7 @@ d=IwAR3wuxdHW8VE30FMaqZ6Iuj9Cs86bRSvmij1e_zDjM6Bwo4l71n5EKcLxqY" "Température chaude" </p> <div class="mb-4 flex flex-row"> - <div class="flex items-center"> + <div class="flex items-center"> <p class="mr-12 text-left font-extrabold text-4xl text-white"> "1" </p> @@ -768,7 +768,7 @@ d=IwAR3wuxdHW8VE30FMaqZ6Iuj9Cs86bRSvmij1e_zDjM6Bwo4l71n5EKcLxqY" </p> </div> <div class="mb-4 flex flex-row"> - <div class="flex items-center"> + <div class="flex items-center"> <p class="mr-12 text-left font-extrabold text-4xl text-white"> "2" </p> @@ -778,7 +778,7 @@ d=IwAR3wuxdHW8VE30FMaqZ6Iuj9Cs86bRSvmij1e_zDjM6Bwo4l71n5EKcLxqY" </p> </div> <div class="mb-4 flex flex-row"> - <div class="flex items-center"> + <div class="flex items-center"> <p class="mr-12 text-left font-extrabold text-4xl text-white"> "3" </p> @@ -788,7 +788,7 @@ d=IwAR3wuxdHW8VE30FMaqZ6Iuj9Cs86bRSvmij1e_zDjM6Bwo4l71n5EKcLxqY" </p> </div> <div class="flex flex-row"> - <div class="flex items-center"> + <div class="flex items-center"> <p class="mr-12 text-left font-extrabold text-4xl text-white"> "4" </p> diff --git a/src/space_colonization/point.rs b/src/space_colonization/point.rs index 43f72f9..e667fdf 100644 --- a/src/space_colonization/point.rs +++ b/src/space_colonization/point.rs @@ -46,20 +46,20 @@ impl Point { impl Ord for Point { fn cmp(&self, other: &Self) -> std::cmp::Ordering { - if self.x > other.x { - return std::cmp::Ordering::Greater; - } - if self.x < other.x { - return std::cmp::Ordering::Less; - } - if self.y > other.y { - return std::cmp::Ordering::Greater; - } - if self.y < other.y { - return std::cmp::Ordering::Less; - } + if self.x > other.x { + return std::cmp::Ordering::Greater; + } + if self.x < other.x { + return std::cmp::Ordering::Less; + } + if self.y > other.y { + return std::cmp::Ordering::Greater; + } + if self.y < other.y { + return std::cmp::Ordering::Less; + } - std::cmp::Ordering::Equal + std::cmp::Ordering::Equal } } @@ -69,169 +69,135 @@ mod tests { #[test] fn distance_to_itself_is_zero() { - let p = Point { - x: 1, - y: 1, - }; + let p = Point { x: 1, y: 1 }; assert_eq!(p.distance(&p), 0.0); } #[test] fn distance_same_x_is_y() { - let p1 = Point { - x: 1, - y: 1, - }; + let p1 = Point { x: 1, y: 1 }; - let p2 = Point { - x: 1, - y: 5, - }; + let p2 = Point { x: 1, y: 5 }; assert_eq!(p1.distance(&p2), 4.0); } #[test] fn distance_same_y_is_x() { - let p1 = Point::new((1,1)); - let p2 = Point::new((5,1)); + let p1 = Point::new((1, 1)); + let p2 = Point::new((5, 1)); assert_eq!(p1.distance(&p2), 4.0); } #[test] fn distance_3_4_5() { - let p1 = Point::new((0,0)); - let p2 = Point::new((3,4)); + let p1 = Point::new((0, 0)); + let p2 = Point::new((3, 4)); assert_eq!(p1.distance(&p2), 5.0); } #[test] fn distance_is_always_positive() { - let p1 = Point::new((10,10)); - let p2 = Point::new((5,10)); + let p1 = Point::new((10, 10)); + let p2 = Point::new((5, 10)); assert_eq!(p1.distance(&p2), 5.0); - let p1 = Point::new((10,10)); - let p2 = Point::new((10,5)); + let p1 = Point::new((10, 10)); + let p2 = Point::new((10, 5)); assert_eq!(p1.distance(&p2), 5.0); } #[test] fn distance_quadrant3() { - let p1 = Point { - x: 3, - y: 4, - }; + let p1 = Point { x: 3, y: 4 }; - let p2 = Point { - x: 0, - y: 0, - }; + let p2 = Point { x: 0, y: 0 }; assert_eq!(p1.distance(&p2), 5.0); } #[test] fn distance_quadrant2() { - let p1 = Point { - x: 3, - y: 4, - }; + let p1 = Point { x: 3, y: 4 }; - let p2 = Point { - x: 0, - y: 100, - }; + let p2 = Point { x: 0, y: 100 }; assert_eq!(p1.distance(&p2) as f32, 96.04687); } #[test] fn distance_quadrant2_fast() { - let p1 = Point { - x: 3, - y: 4, - }; + let p1 = Point { x: 3, y: 4 }; - let p2 = Point { - x: 3, - y: 50, - }; + let p2 = Point { x: 3, y: 50 }; assert_eq!(p1.distance(&p2), 46.0); } #[test] fn distance_quadrant4() { - let p1 = Point { - x: 3, - y: 4, - }; + let p1 = Point { x: 3, y: 4 }; - let p2 = Point { - x: 50, - y: -50, - }; + let p2 = Point { x: 50, y: -50 }; assert_eq!(p1.distance(&p2) as f32, 71.5891); } #[test] fn movement_does_nothing_when_right_length() { - let root = Point::new((0,0)); - let node = Point::new((0,1)); + let root = Point::new((0, 0)); + let node = Point::new((0, 1)); assert_eq!(root.movement(node.clone(), 1), node); } #[test] fn movement_does_not_overlap() { - let root = Point::new((0,1)); - let node = Point::new((0,0)); + let root = Point::new((0, 1)); + let node = Point::new((0, 0)); assert_eq!(root.movement(node.clone(), 2), Point::new((0, -1))); } #[test] fn movement_adjusts_to_asked_length() { - let root = Point::new((0,0)); - let node = Point::new((0,1)); - assert_eq!(root.movement(node, 10), Point::new((0,10))); + let root = Point::new((0, 0)); + let node = Point::new((0, 1)); + assert_eq!(root.movement(node, 10), Point::new((0, 10))); } #[test] fn movement_works_away_from_origin() { - let root = Point::new((10,10)); - let node = Point::new((10,11)); - assert_eq!(root.movement(node, 10), Point::new((10,20))); + let root = Point::new((10, 10)); + let node = Point::new((10, 11)); + assert_eq!(root.movement(node, 10), Point::new((10, 20))); } #[test] fn movement_works_in_two_dimension() { - let root = Point::new((10,10)); - let node = Point::new((40,50)); - assert_eq!(root.movement(node, 50), Point::new((40,50))); + let root = Point::new((10, 10)); + let node = Point::new((40, 50)); + assert_eq!(root.movement(node, 50), Point::new((40, 50))); - let root = Point::new((10,10)); - let node = Point::new((40,50)); - assert_eq!(root.movement(node, 5), Point::new((13,14))); + let root = Point::new((10, 10)); + let node = Point::new((40, 50)); + assert_eq!(root.movement(node, 5), Point::new((13, 14))); } #[test] fn movement_works_in_all_directions() { - let root = Point::new((40,50)); - let node = Point::new((10,10)); - assert_eq!(root.movement(node, 5), Point::new((37,46))); + let root = Point::new((40, 50)); + let node = Point::new((10, 10)); + assert_eq!(root.movement(node, 5), Point::new((37, 46))); - let root = Point::new((50,10)); - let node = Point::new((10,10)); - assert_eq!(root.movement(node, 5), Point::new((45,10))); + let root = Point::new((50, 10)); + let node = Point::new((10, 10)); + assert_eq!(root.movement(node, 5), Point::new((45, 10))); - let root = Point::new((10,50)); - let node = Point::new((10,10)); - assert_eq!(root.movement(node, 5), Point::new((10,45))); + let root = Point::new((10, 50)); + let node = Point::new((10, 10)); + assert_eq!(root.movement(node, 5), Point::new((10, 45))); } } - diff --git a/src/space_colonization/space_colonization.rs b/src/space_colonization/space_colonization.rs index dcb6faf..21fd581 100644 --- a/src/space_colonization/space_colonization.rs +++ b/src/space_colonization/space_colonization.rs @@ -311,7 +311,7 @@ mod test { let mut attractors = Vec::new(); attractors.push(Attractor::new(Point::new((10, 0)))); - let mut sc = SpaceColonization::new_for_tests(100, 100, attractors, |_, _|{}); + let mut sc = SpaceColonization::new_for_tests(100, 100, attractors, |_, _| {}); assert_eq!(sc.attractors.len(), 1); assert!(sc.attractors.iter().find(|a| a.dead == true).is_none()); @@ -357,7 +357,7 @@ mod test { dead: true, }); - let mut sc = SpaceColonization::new_for_tests(100, 100, attractors, |_, _|{}); + let mut sc = SpaceColonization::new_for_tests(100, 100, attractors, |_, _| {}); assert_eq!(sc.attractors.len(), 1); assert!(sc.attractors.iter().find(|a| a.dead == true).is_some()); diff --git a/src/space_colonization/spacial_index.rs b/src/space_colonization/spacial_index.rs index f833ae5..c28fd09 100644 --- a/src/space_colonization/spacial_index.rs +++ b/src/space_colonization/spacial_index.rs @@ -154,8 +154,10 @@ mod test { assert_eq!( index.get_surrounding_elements(&Point::new((50, 50))).sort(), vec![ - &4040, &4545, &5040, &6040, &4050, &5050, &6050, &5050, &5151, &6060, &4060, &5060, &6060, - ].sort() + &4040, &4545, &5040, &6040, &4050, &5050, &6050, &5050, &5151, &6060, &4060, &5060, + &6060, + ] + .sort() ); } From a5a093d7d69368c9661099b8c3e39e771403828d Mon Sep 17 00:00:00 2001 From: jeangab <jg@nationtech.io> Date: Mon, 21 Aug 2023 09:13:43 -0400 Subject: [PATCH 11/11] feat(space_colonization): Spatial index plugged in, performance is much better --- src/components/background.rs | 67 +++--- src/space_colonization/mod.rs | 2 +- src/space_colonization/space_colonization.rs | 88 +++++--- .../space_colonization.rs.bak | 201 ------------------ .../{spacial_index.rs => spatial_index.rs} | 173 +++++++++++---- 5 files changed, 223 insertions(+), 308 deletions(-) delete mode 100644 src/space_colonization/space_colonization.rs.bak rename src/space_colonization/{spacial_index.rs => spatial_index.rs} (52%) diff --git a/src/components/background.rs b/src/components/background.rs index 3c2e41c..48c3135 100644 --- a/src/components/background.rs +++ b/src/components/background.rs @@ -46,26 +46,29 @@ pub fn Background(cx: Scope, class: &'static str) -> impl IntoView { render_node_fn, ); let nodes = Rc::new(RefCell::new(Vec::new())); - nodes.borrow_mut().push(Node::new(Point::new(( - (window_width / 3) as i32, - (window_height / 3) as i32, - )))); - nodes.borrow_mut().push(Node::new(Point::new(( - (window_width / 2) as i32, - (window_height / 3) as i32, - )))); - nodes.borrow_mut().push(Node::new(Point::new(( - (window_width / 3) as i32, - (window_height / 2) as i32, - )))); - nodes.borrow_mut().push(Node::new(Point::new(( - (window_width - 200) as i32, - (window_height / 3) as i32, - )))); - nodes.borrow_mut().push(Node::new(Point::new(( - (window_width - 100) as i32, - (window_height - 100) as i32, - )))); + { + let mut nodesMut = nodes.borrow_mut(); + nodesMut.push(Node::new(Point::new(( + (window_width / 3) as i32, + (window_height / 3) as i32, + )))); + nodesMut.push(Node::new(Point::new(( + (window_width / 2) as i32, + (window_height / 3) as i32, + )))); + nodesMut.push(Node::new(Point::new(( + (window_width / 3) as i32, + (window_height / 2) as i32, + )))); + nodesMut.push(Node::new(Point::new(( + (window_width - 200) as i32, + (window_height / 3) as i32, + )))); + nodesMut.push(Node::new(Point::new(( + (window_width - 100) as i32, + (window_height - 100) as i32, + )))); + } // TODO Resize on window resize log!( "TODO resize on window resize canvas parent size = {} {}", @@ -91,13 +94,16 @@ pub fn Background(cx: Scope, class: &'static str) -> impl IntoView { let end_time = window().unwrap().performance().unwrap().now(); log!( "Rendering nodes and {} attractors took {}", - sc.attractors.len(), + sc.attractors.size(), end_time - start_time ); let context = context.clone(); let closure = Closure::<dyn FnMut(_)>::new(move |_: web_sys::MouseEvent| { let start_time = window().unwrap().performance().unwrap().now(); - sc.grow(&mut nodes.borrow_mut()); + { + let mut nodesMut = nodes.borrow_mut(); + sc.grow(&mut nodesMut); + } // let render_id = window().unwrap().performance().unwrap().now(); // context.begin_path(); // sc.render_nodes(&nodes.borrow(), render_id, render_node_fn); @@ -116,7 +122,7 @@ pub fn Background(cx: Scope, class: &'static str) -> impl IntoView { let end_time = window().unwrap().performance().unwrap().now(); log!( "Rendering nodes and {} attractors took {}", - sc.attractors.len(), + sc.attractors.size(), end_time - start_time ); }); @@ -124,10 +130,17 @@ pub fn Background(cx: Scope, class: &'static str) -> impl IntoView { let window = window().unwrap(); window .set_interval_with_callback_and_timeout_and_arguments_0( - closure.as_ref().unchecked_ref(), - 10, - ) - .unwrap(); + closure.as_ref().unchecked_ref(), + 30, + ) + .unwrap(); + + // window + // .add_event_listener_with_callback( + // "click", + // closure.as_ref().unchecked_ref(), + // ) + // .unwrap(); closure.forget(); }); diff --git a/src/space_colonization/mod.rs b/src/space_colonization/mod.rs index 85b6528..4c6e079 100644 --- a/src/space_colonization/mod.rs +++ b/src/space_colonization/mod.rs @@ -5,7 +5,7 @@ pub use point::*; mod space_colonization; pub use space_colonization::*; mod math; -mod spacial_index; +mod spatial_index; #[wasm_bindgen] extern "C" { diff --git a/src/space_colonization/space_colonization.rs b/src/space_colonization/space_colonization.rs index 21fd581..43598f1 100644 --- a/src/space_colonization/space_colonization.rs +++ b/src/space_colonization/space_colonization.rs @@ -1,4 +1,5 @@ use super::math::calculate_new_node_position; +use super::spatial_index::SpatialIndex; use super::Attraction; use super::{Attractor, Node, Point}; use log::info; @@ -44,7 +45,7 @@ where /// /// If density is 10, then there will be an average distance of 10 between attractors density: i32, - pub attractors: Vec<Attractor>, + pub attractors: SpatialIndex<Attractor>, render_fn: F, } @@ -56,7 +57,8 @@ where where F: Fn(&Node, &Node), { - let attractors = Vec::new(); + let attraction_distance = 100; + let attractors = SpatialIndex::new(Point::new((width, height)), attraction_distance); let mut sc = SpaceColonization { max_point: Point { @@ -64,7 +66,7 @@ where y: height, }, kill_distance: 5.0, - attraction_distance: 100, + attraction_distance, segment_length: 5, density: 30, attractors, @@ -80,7 +82,7 @@ where pub fn new_for_tests( width: i32, height: i32, - attractors: Vec<Attractor>, + attractors: SpatialIndex<Attractor>, render_fn: F, ) -> SpaceColonization<F> where @@ -115,9 +117,8 @@ where let mut y_pos = 0; while x_pos < self.max_point.x { while y_pos < self.max_point.y { - self.attractors.push(Attractor::new( - self.get_random_point(x_pos.into(), y_pos.into()), - )); + let point = self.get_random_point(x_pos.into(), y_pos.into()); + self.attractors.add(&point, Attractor::new(point)); y_pos += self.density; } x_pos += self.density; @@ -150,7 +151,6 @@ where } pub fn grow<'b>(&mut self, mut nodes: &'b mut Vec<Node>) { - info!("Growing nodes {:?}", nodes); self.grow_nodes(&mut nodes) } @@ -207,11 +207,6 @@ where // have learned quite a lot about how rust programs work and should be designed. unsafe { - /* - let segfault_boy: *const u8 = usize::MAX as *const u8; - let memory_content = *segfault_boy; - println!("memory content at address 0 {}", memory_content); - */ let new_point = calculate_new_node_position(&(**node), attractor, self.segment_length); if let Some(new_point) = new_point { @@ -262,10 +257,17 @@ where fn find_attractors_in_range(&mut self, n: &Node) -> Vec<(*mut Attractor, f64)> { let mut attractors_in_range = Vec::new(); - for a in self.attractors.iter_mut().filter(|a| !a.dead) { - let distance = n.position.distance(&a.position); + for a in self + .attractors + .get_surrounding_elements_with_filter(&n.position, |a| !a.dead) + .iter() + { + let distance; + unsafe { + distance = n.position.distance(&(**a).position); + } if distance < self.attraction_distance as f64 { - attractors_in_range.push((a as *mut Attractor, distance)); + attractors_in_range.push((*a, distance)); } } attractors_in_range @@ -308,13 +310,18 @@ mod test { fn grow_should_reach_single_attractor_and_die() { let mut nodes = Vec::new(); nodes.push(Node::new(Point::new((0, 0)))); - let mut attractors = Vec::new(); - attractors.push(Attractor::new(Point::new((10, 0)))); + let mut attractors = SpatialIndex::new(Point::new((100, 100)), 10); + let point = Point::new((10, 0)); + attractors.add(&point, Attractor::new(point)); let mut sc = SpaceColonization::new_for_tests(100, 100, attractors, |_, _| {}); - assert_eq!(sc.attractors.len(), 1); - assert!(sc.attractors.iter().find(|a| a.dead == true).is_none()); + assert_eq!( + sc.attractors + .get_surrounding_elements_with_filter(&point, |_| true) + .len(), + 1 + ); println!("before grow"); dbg!(&nodes); @@ -322,7 +329,13 @@ mod test { println!("after grow 1"); dbg!(&nodes); - assert!(sc.attractors.iter().find(|a| a.dead == true).is_none()); + assert_eq!( + sc.attractors + .get_surrounding_elements_with_filter(&point, |a| a.dead == false) + .len(), + 1 + ); + sc.grow(&mut nodes); println!("after grow 2"); @@ -336,12 +349,15 @@ mod test { (Point::new((3, 0)), Point::new((6, 0))), ]), ); - assert_eq!( sc.attractors - .iter() - .filter(|a| a.dead == true) - .collect::<Vec<&Attractor>>() + .get_surrounding_elements_with_filter(&point, |a| a.dead == false) + .len(), + 0 + ); + assert_eq!( + sc.attractors + .get_surrounding_elements_with_filter(&point, |a| a.dead == true) .len(), 1 ); @@ -351,16 +367,24 @@ mod test { fn grow_should_ignore_dead_attractors() { let mut nodes = Vec::new(); nodes.push(Node::new(Point::new((0, 0)))); - let mut attractors = Vec::new(); - attractors.push(Attractor { - position: Point::new((10, 0)), - dead: true, - }); + let mut attractors = SpatialIndex::new(Point::new((100, 100)), 10); + let point = Point::new((10, 0)); + attractors.add( + &point, + Attractor { + position: point, + dead: true, + }, + ); let mut sc = SpaceColonization::new_for_tests(100, 100, attractors, |_, _| {}); - assert_eq!(sc.attractors.len(), 1); - assert!(sc.attractors.iter().find(|a| a.dead == true).is_some()); + assert_eq!( + sc.attractors + .get_surrounding_elements_with_filter(&Point::new((10, 0)), |a| a.dead == true) + .len(), + 1 + ); sc.grow(&mut nodes); diff --git a/src/space_colonization/space_colonization.rs.bak b/src/space_colonization/space_colonization.rs.bak deleted file mode 100644 index 8692413..0000000 --- a/src/space_colonization/space_colonization.rs.bak +++ /dev/null @@ -1,201 +0,0 @@ -use std::sync::RwLock; - -use super::{Attractor, Node, Point}; -use rand::thread_rng; -use rand::Rng; -use web_sys::console; -use web_sys::window; - -pub struct SpaceColonization { - max_point: Point, - /// When a node grows within kill_distance of an attractor, the attractor is killed - kill_distance: i32, - /// Maximum distance between an attractor and a node for the node to - /// be affected by the attractor. - /// - /// Must be greater than sqrt((density)**2 + (density)**2) - attraction_distance: i32, - segment_length: i32, - /// Size of the cells on which attractors are placed. - /// - /// If density is 10, then there will be an average distance of 10 between attractors - density: i32, - pub root_nodes: Vec<RwLock<Node>>, - pub attractors: Vec<RwLock<Attractor>>, -} - -impl SpaceColonization { - pub fn new(width: i32, height: i32) -> SpaceColonization { - let mut root_nodes = Vec::new(); - root_nodes.push(RwLock::new(Node { - position: Point { x: 100, y: 100 }, - children: Vec::new(), - })); - let attractors = Vec::new(); - - let mut sc = SpaceColonization { - max_point: Point { - x: width, - y: height, - }, - kill_distance: 10, - attraction_distance: 43, - segment_length: 5, - density: 30, - root_nodes, - attractors, - }; - - sc.place_attractors(); - - return sc; - } - - pub fn render_nodes<F>(&self, render_id: f64, render_fn: F) - where - F: Copy + Fn(&Node, &Node), - { - for n in self.root_nodes.iter() { - n.read().unwrap().render(render_id, render_fn); - } - } - - fn place_attractors(&mut self) { - let start_time = window().unwrap().performance().unwrap().now(); - console::log_1(&format!("Start placing attractors {}", start_time).into()); - let mut x_pos = 0; - let mut y_pos = 0; - while x_pos < self.max_point.x { - while y_pos < self.max_point.y { - self.attractors.push(RwLock::new(Attractor { - position: self.get_random_point(x_pos.into(), y_pos.into()), - dead: false, - })); - y_pos += self.density; - } - x_pos += self.density; - y_pos = 0; - } - let end_time = window().unwrap().performance().unwrap().now(); - let elapsed = end_time - start_time; - console::log_1(&format!("Done placing attractors , took : {}", elapsed).into()); - } - - fn get_random_point(&self, x_pos: i32, y_pos: i32) -> Point { - let half_density: i32 = (self.density / 2).into(); - let mut x_min = x_pos - half_density; - if x_min < 0 { - x_min = 0; - } - - let mut y_min = y_pos - half_density; - if y_min < 0 { - y_min = 0; - } - - Point { - x: thread_rng() - .gen_range(x_min..x_pos + half_density) - .try_into() - .unwrap(), - y: thread_rng() - .gen_range(y_min..y_pos + half_density) - .try_into() - .unwrap(), - } - } - - pub fn grow(&self) { - for n in self.root_nodes.iter() { - self.grow_node(n); - } - // iterate through the list of nodes that are not dead yet (still had an active attractor - // previous iteration) - // For each node : - // find attractors within attraction distance of node - // calculate distance to affecting attractors - // determine how many new nodes grow from here - // determine position of new nodes - // remove current node from leaves list - } - - fn grow_node(&self, n: &RwLock<Node>) { - n.read() - .unwrap() - .children - .iter() - .for_each(|n| self.grow_node(n)); - let affecting_attractors = self.find_affecting_attractors(&n); - console::log_1( - &format!("Found {} affecting attractors", affecting_attractors.len()).into(), - ); - let new_node = self.create_new_node(n, &affecting_attractors); - for a in affecting_attractors { - let mut a = a.write().unwrap(); - if n.read().unwrap().position.distance(&a.position) < self.kill_distance as f64 { - a.dead = true; - } - } - console::log_1(&format!("New node {:?}", new_node).into()); - n.write().unwrap().children.push(RwLock::new(new_node)); - } - - fn find_affecting_attractors(&self, n: &RwLock<Node>) -> Vec<&RwLock<Attractor>> { - let mut affecting = Vec::new(); - for a in self.attractors.iter() { - let aread = a.read().unwrap(); - // TODO remove attractors instead of marking them dead - // used to display them at the moment but could also be moved - // to a dead queue - if aread.dead { - continue; - } - - let n_distance = n.read().unwrap().position.distance(&aread.position); - // todo for some reason I cannot verify closest node to attractor here - if n_distance < self.attraction_distance.into() && self.is_closest_node(&n.read().unwrap(), &aread) { - affecting.push(a) - } - } - - affecting - } - - fn create_new_node( - &self, - n: &RwLock<Node>, - affecting_attractors: &Vec<&RwLock<Attractor>>, - ) -> Node { - let n = n.read().unwrap(); - let mut attraction_sum_x = 0; - let mut attraction_sum_y = 0; - for a in affecting_attractors.iter() { - attraction_sum_x += n.position.x - a.read().unwrap().position.x; - attraction_sum_y += n.position.y - a.read().unwrap().position.y; - } - - Node { - position: Point { - x: n.position.x + attraction_sum_x / affecting_attractors.len() as i32, - y: n.position.y + attraction_sum_y / affecting_attractors.len() as i32, - }, - children: Vec::new(), - } - } - - fn is_closest_node(&self, node: &Node, a: &Attractor) -> bool { - let node_distance = node.position.distance(&a.position); - for n in self.root_nodes.iter() { - let n_read = match n.read() { - Ok(val) => val, - Err(e) => todo!("Cannot read node {}", e), - }; - if n_read.position.distance(&a.position) < node_distance { - return false; - } - // todo iterate the entire tree - todo!(); - } - return true; - } -} diff --git a/src/space_colonization/spacial_index.rs b/src/space_colonization/spatial_index.rs similarity index 52% rename from src/space_colonization/spacial_index.rs rename to src/space_colonization/spatial_index.rs index c28fd09..c4246fc 100644 --- a/src/space_colonization/spacial_index.rs +++ b/src/space_colonization/spatial_index.rs @@ -1,13 +1,14 @@ use super::Point; #[derive(Debug)] -struct SpatialIndex<T> { +pub struct SpatialIndex<T> { elements: Vec<Vec<T>>, /// The number of cells between a cell and the cell right below it. /// /// For a table of 100x100 with cell_size = 10, number_cells_x is 11 (100/10+1) number_cells_x: i32, cell_size: i32, + size: u32, max_point: Point, } @@ -32,6 +33,7 @@ where elements, cell_size, number_cells_x, + size: 0, max_point, } } @@ -45,18 +47,45 @@ where .get_mut(element_index as usize) .unwrap() .push(element); + self.size += 1; } - pub fn get_surrounding_elements<'a>(&'a self, point: &Point) -> Vec<&'a T> { + pub fn size(&self) -> u32 { + self.size + } + + /// Fetches elements in the cell corresponding to point and all the adjacent cells + /// filtering returned elements with filter + /// + /// May panic or return wrong values if the point is outside this SpatialIndex max point + pub fn get_surrounding_elements_with_filter<'a, F>( + self: &'a mut Self, + point: &Point, + mut filter: F, + ) -> Vec<*mut T> + where + F: FnMut(&T) -> bool, + { let surrounding_indices: Vec<usize> = self.get_surrounding_indices(point); - let mut surrounding_elements = Vec::new(); - dbg!(&surrounding_indices); - for i in surrounding_indices { - surrounding_elements.extend(self.elements.get(i).unwrap().iter()); + let mut surrounding_elements: Vec<*mut T> = Vec::new(); + for i in surrounding_indices.iter() { + println!("elements len {}", self.elements.len()); + let elements_for_index = self + .elements + .get_mut(*i as usize) + .expect( + format!( + "point {:?} is in range for spatial_index with max_point {:?}, currently getting index {}, among surrounding indices {:?}", + point, self.max_point, i, surrounding_indices + ) + .as_str(), + ); + let elements_for_index = elements_for_index + .iter_mut() + .filter(|el| filter(el)) + .map(|el| el as *mut T); + surrounding_elements.extend(elements_for_index); } - dbg!(&self.elements[115]); - dbg!(&surrounding_elements); - dbg!(&self.elements.len()); surrounding_elements } @@ -69,6 +98,9 @@ where let mut indices = Vec::from([element_index]); let row_offset = self.number_cells_x as usize; + let last_cell_x_start = self.max_point.x - (self.max_point.x % self.cell_size); + let last_row_y_min = self.max_point.y - (self.max_point.y % self.cell_size); + // top row if point.y >= self.cell_size { // top left @@ -78,7 +110,7 @@ where // top middle indices.push(element_index - row_offset); // top right - if point.x < self.max_point.x { + if point.x < last_cell_x_start { indices.push(element_index - row_offset + 1); } } @@ -90,11 +122,11 @@ where // middle middle can be skipped, already added // middle right - if point.x < self.max_point.x { + if point.x < last_cell_x_start { indices.push(element_index + 1); } - if point.y < self.max_point.y { + if point.y < last_row_y_min { // bottom left if point.x >= self.cell_size { indices.push(element_index + row_offset - 1); @@ -103,7 +135,7 @@ where // bottom middle indices.push(element_index + row_offset); // bottom right - if point.x < self.max_point.x { + if point.x < last_cell_x_start { indices.push(element_index + row_offset + 1); } } @@ -116,12 +148,21 @@ where mod test { use super::*; + fn assert_vec_values(actual: Vec<*mut usize>, expected: Vec<usize>) { + let resolved_actual: Vec<usize>; + unsafe { + resolved_actual = actual.iter().map(|n| **n).collect(); + } + + assert_eq!(resolved_actual, expected); + } + #[test] fn when_no_element_surrounding_nodes_returns_empty_vec() { - let index: SpatialIndex<usize> = SpatialIndex::new(Point::new((100, 100)), 10); + let mut index: SpatialIndex<usize> = SpatialIndex::new(Point::new((100, 100)), 10); assert_eq!( - index.get_surrounding_elements(&Point::new((0, 0))), - Vec::<&usize>::new() + index.get_surrounding_elements_with_filter(&Point::new((0, 0)), |_| true), + Vec::<*mut usize>::new() ); } @@ -129,9 +170,9 @@ mod test { fn added_point_is_surrounding_itself() { let mut index: SpatialIndex<usize> = SpatialIndex::new(Point::new((100, 100)), 10); index.add(&Point::new((50, 50)), 132); - assert_eq!( - index.get_surrounding_elements(&Point::new((50, 50))), - vec![&132] + assert_vec_values( + index.get_surrounding_elements_with_filter(&Point::new((50, 50)), |_| true), + vec![132], ); } @@ -152,7 +193,9 @@ mod test { index.add(&Point::new((50, 60)), 5060); index.add(&Point::new((60, 60)), 6060); assert_eq!( - index.get_surrounding_elements(&Point::new((50, 50))).sort(), + index + .get_surrounding_elements_with_filter(&Point::new((50, 50)), |_| true) + .sort(), vec![ &4040, &4545, &5040, &6040, &4050, &5050, &6050, &5050, &5151, &6060, &4060, &5060, &6060, @@ -165,13 +208,13 @@ mod test { fn point_on_top_edge_is_close_to_first_cell() { let mut index: SpatialIndex<usize> = SpatialIndex::new(Point::new((100, 100)), 10); index.add(&Point::new((50, 0)), 132); - assert_eq!( - index.get_surrounding_elements(&Point::new((50, 9))), - vec![&132] + assert_vec_values( + index.get_surrounding_elements_with_filter(&Point::new((50, 9)), |_| true), + vec![132], ); - assert_eq!( - index.get_surrounding_elements(&Point::new((50, 0))), - vec![&132] + assert_vec_values( + index.get_surrounding_elements_with_filter(&Point::new((50, 0)), |_| true), + vec![132], ); } @@ -179,13 +222,13 @@ mod test { fn point_on_bottom_edge_is_close_to_bottom_cell() { let mut index: SpatialIndex<usize> = SpatialIndex::new(Point::new((100, 100)), 10); index.add(&Point::new((50, 100)), 132); - assert_eq!( - index.get_surrounding_elements(&Point::new((50, 95))), - vec![&132] + assert_vec_values( + index.get_surrounding_elements_with_filter(&Point::new((50, 95)), |_| true), + vec![132], ); - assert_eq!( - index.get_surrounding_elements(&Point::new((50, 100))), - vec![&132] + assert_vec_values( + index.get_surrounding_elements_with_filter(&Point::new((50, 100)), |_| true), + vec![132], ); } @@ -193,26 +236,26 @@ mod test { fn point_on_right_edge_is_close_to_first_cell() { let mut index: SpatialIndex<usize> = SpatialIndex::new(Point::new((100, 100)), 10); index.add(&Point::new((100, 50)), 132); - assert_eq!( - index.get_surrounding_elements(&Point::new((95, 50))), - vec![&132] + assert_vec_values( + index.get_surrounding_elements_with_filter(&Point::new((95, 50)), |_| true), + vec![132], ); - assert_eq!( - index.get_surrounding_elements(&Point::new((100, 50))), - vec![&132] + assert_vec_values( + index.get_surrounding_elements_with_filter(&Point::new((100, 50)), |_| true), + vec![132], ); } #[test] fn point_on_left_edge_is_close_to_first_cell() { let mut index: SpatialIndex<usize> = SpatialIndex::new(Point::new((100, 100)), 10); index.add(&Point::new((0, 50)), 132); - assert_eq!( - index.get_surrounding_elements(&Point::new((9, 50))), - vec![&132] + assert_vec_values( + index.get_surrounding_elements_with_filter(&Point::new((9, 50)), |_| true), + vec![132], ); - assert_eq!( - index.get_surrounding_elements(&Point::new((0, 50))), - vec![&132] + assert_vec_values( + index.get_surrounding_elements_with_filter(&Point::new((0, 50)), |_| true), + vec![132], ); } @@ -220,9 +263,45 @@ mod test { fn when_elements_too_far_surrounding_is_empty() { let mut index: SpatialIndex<usize> = SpatialIndex::new(Point::new((100, 100)), 10); index.add(&Point::new((0, 0)), 132); - assert_eq!( - index.get_surrounding_elements(&Point::new((99, 99))), - Vec::<&usize>::new() + assert_vec_values( + index.get_surrounding_elements_with_filter(&Point::new((99, 99)), |_| true), + Vec::<usize>::new(), + ); + } + + #[test] + fn works_when_max_point_is_not_multiple_of_cell_size() { + let cell_size = 100; + let mut index: SpatialIndex<usize> = SpatialIndex::new(Point::new((1920, 580)), cell_size); + for x_cell in 0..19 as usize { + for y_cell in 0..5 as usize { + index.add( + &Point::new((x_cell as i32 * cell_size, y_cell as i32 * cell_size)), + x_cell * 100 + y_cell, + ); + } + } + assert_vec_values( + index.get_surrounding_elements_with_filter(&Point::new((1833, 502)), |_| true), + vec![1905, 1904, 1805, 1804] + ); + } + + #[test] + fn works_when_max_point_is_not_multiple_of_cell_size() { + let cell_size = 100; + let mut index: SpatialIndex<usize> = SpatialIndex::new(Point::new((1920, 580)), cell_size); + for x_cell in 0..19 as usize { + for y_cell in 0..5 as usize { + index.add( + &Point::new((x_cell as i32 * cell_size, y_cell as i32 * cell_size)), + x_cell * 100 + y_cell, + ); + } + } + assert_vec_values( + index.get_surrounding_elements_with_filter(&Point::new((1833, 502)), |_| true), + vec![1905, 1904, 1805, 1804] ); } }