diff --git a/Cargo.lock b/Cargo.lock index 9257850..6e6570b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1762,6 +1762,7 @@ dependencies = [ "approx 0.5.1", "eyre", "itertools", + "nannou", "num-traits", "ordered-float 5.0.0", "rand 0.9.1", diff --git a/Cargo.toml b/Cargo.toml index 53fd807..447ac84 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,8 @@ itertools = "0.14.0" num-traits = "0.2.19" rand = "0.9.1" rand_chacha = "0.9.0" +nannou = "0.19.0" +nannou_egui = "0.19.0" [workspace] members = [ diff --git a/README.md b/README.md index a99fe35..01a13bd 100644 --- a/README.md +++ b/README.md @@ -42,3 +42,9 @@ assert_eq!(results.len(), 2); To run the `nannou` app, run `cargo run --bin visualize`. ![](assets/vis.gif) + +# Features + +There is a feature `nannou` on `quadtree` that provides: +- calling `regions()` on a QuadTree to return all regions stored under all sub-trees, useful for debug/visualisation +- provide Into/From between `quadtree::Region` and `nannou::geom::Rect` \ No newline at end of file diff --git a/quadtree/Cargo.toml b/quadtree/Cargo.toml index d3b410d..08e52ba 100644 --- a/quadtree/Cargo.toml +++ b/quadtree/Cargo.toml @@ -9,9 +9,13 @@ eyre.workspace = true itertools.workspace = true num-traits.workspace = true rand.workspace = true -ordered-float = {version= "5.0.0", features=["serde"]} +ordered-float = { version = "5.0.0", features = ["serde"] } rand_chacha.workspace = true serdev = "0.2.0" +nannou = {workspace = true, optional = true} + +[features] +nannou = ["dep:nannou"] [dev-dependencies] serde_json = "1.0.140" diff --git a/quadtree/src/quadtree.rs b/quadtree/src/quadtree.rs index 6fd2796..0a90fee 100644 --- a/quadtree/src/quadtree.rs +++ b/quadtree/src/quadtree.rs @@ -131,6 +131,7 @@ impl> QuadTree { } /// Returns all regions + #[cfg(feature = "nannou")] pub fn regions(&self) -> Vec> { let mut regions = vec![self.region.clone()]; diff --git a/quadtree/src/region.rs b/quadtree/src/region.rs index d4c6a9b..293244f 100644 --- a/quadtree/src/region.rs +++ b/quadtree/src/region.rs @@ -88,6 +88,35 @@ impl Query for Region { } } +#[cfg(feature = "nannou")] +impl From<&Region<2>> for nannou::geom::Rect { + fn from(region: &Region<2>) -> Self { + // Convert the region to a Rect + nannou::geom::Rect::from_corners( + nannou::geom::pt2( + *region.intervals()[0].start() as f32, + *region.intervals()[1].start() as f32, + ), + nannou::geom::pt2( + *region.intervals()[0].end() as f32, + *region.intervals()[1].end() as f32, + ), + ) + } +} + +#[cfg(feature = "nannou")] +impl From for Region<2> { + fn from(rect: nannou::geom::Rect) -> Self { + Region::new(&[ + Interval::try_new(rect.left() as f64, rect.right() as f64) + .expect("valid Rect produces valid x-axis"), + Interval::try_new(rect.bottom() as f64, rect.top() as f64) + .expect("valid Rect produces valid y-axis"), + ]) + } +} + /// Demonstrates region containment with correct and incorrect point dimensions. /// /// This compiles: diff --git a/visualize/Cargo.toml b/visualize/Cargo.toml index 4b8ff86..0da98c2 100644 --- a/visualize/Cargo.toml +++ b/visualize/Cargo.toml @@ -4,8 +4,8 @@ version = "0.1.0" edition = "2024" [dependencies] -quadtree = {path = "../quadtree"} +quadtree = {path = "../quadtree", features=["nannou"]} rand.workspace = true eyre.workspace = true -nannou = "0.19.0" -nannou_egui = "0.19.0" +nannou.workspace = true +nannou_egui.workspace = true diff --git a/visualize/src/model.rs b/visualize/src/model.rs index c35aea1..ffa63fc 100644 --- a/visualize/src/model.rs +++ b/visualize/src/model.rs @@ -3,14 +3,14 @@ extern crate nannou; use std::collections::HashSet; use std::num::NonZeroUsize; -use eyre::{Context, Result}; +use eyre::Result; use nannou::Draw; use nannou::geom::Rect; use nannou_egui::Egui; use quadtree::QuadTree; +use quadtree::point::Point; use quadtree::region::Region; -use quadtree::{interval::Interval, point::Point}; use rand::SeedableRng; use rand::rngs::StdRng; @@ -39,12 +39,7 @@ pub struct Model { impl Model { pub fn try_new(egui: Egui, rect: Rect) -> Result { // Create a region from the Rect - let region = Region::new(&[ - Interval::try_new(rect.left() as f64, rect.right() as f64) - .context("converting rect to Interval")?, - Interval::try_new(rect.bottom() as f64, rect.top() as f64) - .context("converting rect to Interval")?, - ]); + let region: Region<2> = rect.into(); Ok(Self { egui, points: Vec::new(), @@ -121,7 +116,7 @@ impl Model { // Draw the quadtree regions for region in qt.regions().iter() { - let rect = region_to_rect(region); + let rect: Rect = region.into(); draw.rect() .xy(rect.xy()) .wh(rect.wh()) @@ -131,17 +126,3 @@ impl Model { } } } - -fn region_to_rect(region: &Region<2>) -> Rect { - // Convert the region to a Rect - Rect::from_corners( - pt2( - *region.intervals()[0].start() as f32, - *region.intervals()[1].start() as f32, - ), - pt2( - *region.intervals()[0].end() as f32, - *region.intervals()[1].end() as f32, - ), - ) -}