Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3,090 changes: 2,934 additions & 156 deletions Cargo.lock

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,9 @@ let results: Vec<_> = quadtree.query(&query_region).collect();

assert_eq!(results.len(), 2);
```

# Visualisation

To run the `nannou` app, run `cargo run --bin visualize`.

![](assets/vis.gif)
Binary file added assets/vis.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
223 changes: 0 additions & 223 deletions quadtree/Cargo.lock

This file was deleted.

2 changes: 2 additions & 0 deletions quadtree/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ pub mod point;
pub mod quadtree;
pub mod query;
pub mod region;

pub use quadtree::QuadTree;
5 changes: 4 additions & 1 deletion visualize/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,7 @@ edition = "2024"

[dependencies]
quadtree = {path = "../quadtree"}
eyre.workspace = true
rand.workspace = true
eyre.workspace = true
nannou = "0.19.0"
nannou_egui = "0.19.0"
2 changes: 2 additions & 0 deletions visualize/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub(crate) mod model;
pub use model::{Model, Technique};
106 changes: 83 additions & 23 deletions visualize/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,91 @@
use eyre::OptionExt;
use eyre::Result;
use quadtree::{interval::Interval, point::Point, quadtree::QuadTree, region::Region};
extern crate nannou;

use std::num::NonZero;
use nannou::{event::ElementState, prelude::*, winit::event::WindowEvent};
use nannou_egui::Egui;
use quadtree::point::Point;
use visualize::Model;

fn main() -> Result<()> {
// Create a region (the bounds of the quadtree)
let region = Region::new(&[
Interval::try_new(0.0, 10.0)?, // X-axis
Interval::try_new(0.0, 10.0)?, // Y-axis
]);
fn main() {
nannou::app(create_model).update(update).run();
}

fn create_model(app: &App) -> Model {
// Create window
let window_id = app
.new_window()
.view(view)
.raw_event(raw_window_event)
.build()
.unwrap();
let window = app.window(window_id).unwrap();

let egui = Egui::from_window(&window);

Model::try_new(egui, app.window_rect()).expect("valid Rect from app")
}

fn raw_window_event(app: &App, model: &mut Model, event: &WindowEvent) {
// Let egui handle things like keyboard and mouse input.
model.egui.handle_raw_event(event);
model.mouse_position = None;

// Get the egui context
let ctx = model.egui.ctx();

// Initialise the QuadTree
let mut quadtree = QuadTree::new(&region, NonZero::new(4).ok_or_eyre("value must be > 0")?);
// Handle mouse input
if let WindowEvent::MouseInput { state, button, .. } = event {
let point = Point::new(&[app.mouse.x, app.mouse.y]);
model.mouse_position = Some(point);
if !ctx.wants_pointer_input() {
// Only add points if egui is not handling the pointer input

// Insert points into the QuadTree
for i in 0..4 {
quadtree.insert(Point::new(&[i, 0]))?;
// Left-click (adding point manually)
if *button == MouseButton::Left && *state == ElementState::Pressed {
model.add_point(point);
}
// Right-click (adding random points)
if *button == MouseButton::Right && *state == ElementState::Pressed {
model.add_random_points(500);
}
}
} else if let WindowEvent::CursorMoved { .. } = event {
let point = Point::new(&[app.mouse.x, app.mouse.y]);
model.mouse_position = Some(point);
}
}

fn update(_app: &App, model: &mut Model, _update: Update) {
let egui = &mut model.egui;
let _ctx = egui.begin_frame();
}

fn view(app: &App, model: &Model, frame: Frame) {
frame.clear(WHITE);

// Prepare to draw.
let draw = app.draw();

// Draw the points, mouse query circle and QuadTree rectangles
model.draw_app(&draw, &model.points);

// Draw FPS counter
let fps = app.fps();
draw.text(&format!("FPS: {:.0}", fps))
.x_y(
app.window_rect().right() - 50.0,
app.window_rect().top() - 20.0,
) // Position in top-right
.color(BLACK)
.font_size(20);

// Query quadtree
let query_region = Region::new(&[Interval::try_new(0.0, 2.0)?, Interval::try_new(0.0, 10.0)?]);
let results: Vec<_> = quadtree.query(&query_region).collect();
// Add help instructions
draw.text("Left-click to add a point, Right-click to add random points")
.x_y(0.0, app.window_rect().bottom() + 20.0)
.width(500.0)
.color(BLACK)
.font_size(14);

println!(
"There are {} points within the distance query",
results.len()
);
Ok(())
// Write to the window frame and draw the egui menu.
draw.to_frame(app, &frame).unwrap();
model.egui.draw_to_frame(&frame).unwrap();
}
Loading