Skip to content

Commit c8cafff

Browse files
authored
Merge pull request #1 from jo56/fixing-cleanup
Adding additional patterns and post-test release fixes
2 parents 7a6f001 + 097c02b commit c8cafff

38 files changed

Lines changed: 5752 additions & 126 deletions

.claude/settings.local.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,14 @@
33
"allow": [
44
"WebFetch(domain:github.com)",
55
"Bash(cargo build:*)",
6-
"Bash(tree:*)"
6+
"Bash(tree:*)",
7+
"WebFetch(domain:raw.githubusercontent.com)",
8+
"Bash(cargo check:*)",
9+
"Bash(cargo run:*)",
10+
"Bash(RUST_BACKTRACE=1 cargo run)",
11+
"Bash(set RUST_BACKTRACE=1)",
12+
"Bash(timeout:*)",
13+
"Bash(cargo fix:*)"
714
],
815
"deny": [],
916
"ask": []

sim-app/src/main.rs

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
// Hide console window on Windows in release builds
2+
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
3+
14
mod viewer_2d;
25
mod viewer_3d;
36

@@ -8,6 +11,7 @@ fn main() -> eframe::Result {
811
let options = eframe::NativeOptions {
912
viewport: egui::ViewportBuilder::default()
1013
.with_inner_size([1280.0, 800.0])
14+
.with_position([200.0, 50.0])
1115
.with_title("Complex Systems Visualizer"),
1216
..Default::default()
1317
};
@@ -42,9 +46,15 @@ impl ComplexSystemsApp {
4246
Box::new(julia::Julia::new()),
4347
Box::new(burning_ship::BurningShip::new()),
4448

45-
// Cellular Systems
49+
// Cellular Systems & Emergent Complexity
4650
Box::new(game_of_life::GameOfLife::new()),
4751
Box::new(cellular_automaton::CellularAutomaton::new(30)),
52+
Box::new(langtons_ant::LangtonsAnt::new()),
53+
Box::new(cyclic_ca::CyclicCA::new()),
54+
55+
// Growth & Self-Organization
56+
Box::new(dla::DLA::new()),
57+
Box::new(sandpile::Sandpile::new()),
4858

4959
// Animated Simulations
5060
Box::new(double_pendulum::DoublePendulum::new()),
@@ -59,9 +69,22 @@ impl ComplexSystemsApp {
5969
Box::new(generative::Boids::new()),
6070
Box::new(generative::DeJongAttractor::new()),
6171
Box::new(generative::CliffordAttractor::new()),
72+
73+
// Complex Emergent Simulations
74+
Box::new(slime_mold::SlimeMold::new()),
75+
Box::new(falling_sand::FallingSand::new()),
6276
];
6377

6478
let simulations_3d: Vec<Simulation3DBox> = vec![
79+
// Stunning 3D Visualizations
80+
Box::new(dna_helix::DNAHelix::new()),
81+
Box::new(torus_knot::TorusKnot::new()),
82+
Box::new(galaxy_spiral::GalaxySpiral::new()),
83+
84+
// Enhanced Particle Systems
85+
Box::new(particle_attractor_3d::ParticleAttractor3D::new()),
86+
Box::new(boids_3d::Boids3D::new()),
87+
6588
// Classic Attractors
6689
Box::new(lorenz::LorenzAttractor::new()),
6790
Box::new(rossler::RosslerAttractor::new()),
@@ -72,6 +95,16 @@ impl ComplexSystemsApp {
7295
Box::new(dadras::DadrasAttractor::new()),
7396
Box::new(thomas::ThomasAttractor::new()),
7497
Box::new(chen::ChenAttractor::new()),
98+
99+
// Diverse Particle Simulations
100+
Box::new(nbody_gravity::NBodyGravity::new()),
101+
Box::new(fluid_sph::FluidSPH::new()),
102+
Box::new(magnetic_field::MagneticField::new()),
103+
104+
// Radical 3D Animations
105+
Box::new(vortex_turbulence::VortexTurbulence::new()),
106+
Box::new(lightning_bolt::LightningBolt::new()),
107+
Box::new(fractal_tree_3d::FractalTree3D::new()),
75108
];
76109

77110
Self {
@@ -112,6 +145,45 @@ impl eframe::App for ComplexSystemsApp {
112145

113146
ui.separator();
114147

148+
// Global scale/zoom controls
149+
match self.sim_type {
150+
SimulationType::TwoD => {
151+
ui.horizontal(|ui| {
152+
ui.label("🔍 Pattern Detail:");
153+
if ui.add(egui::Slider::new(&mut self.viewer_2d.scale, 0.25..=2.0)
154+
.text("Scale")).changed() {
155+
self.viewer_2d.needs_update = true;
156+
// Reset pan when scale changes to prevent shift
157+
self.viewer_2d.pan_x = 0.0;
158+
self.viewer_2d.pan_y = 0.0;
159+
}
160+
if ui.button("Reset Scale").clicked() {
161+
self.viewer_2d.scale = 1.0;
162+
self.viewer_2d.needs_update = true;
163+
self.viewer_2d.pan_x = 0.0;
164+
self.viewer_2d.pan_y = 0.0;
165+
}
166+
if ui.button("Reset Pan").clicked() {
167+
self.viewer_2d.pan_x = 0.0;
168+
self.viewer_2d.pan_y = 0.0;
169+
}
170+
});
171+
ui.label(format!("📐 Resolution: {}x{} pixels",
172+
(800.0 * self.viewer_2d.scale) as i32,
173+
(600.0 * self.viewer_2d.scale) as i32));
174+
ui.label("💡 Tip: Drag to pan when zoomed");
175+
}
176+
SimulationType::ThreeD => {
177+
ui.horizontal(|ui| {
178+
ui.label("🔍 View Zoom:");
179+
ui.add(egui::Slider::new(&mut self.viewer_3d.zoom, 0.5..=5.0)
180+
.text("Zoom"));
181+
});
182+
}
183+
}
184+
185+
ui.separator();
186+
115187
egui::ScrollArea::vertical().show(ui, |ui| {
116188

117189
match self.sim_type {
@@ -162,7 +234,7 @@ impl eframe::App for ComplexSystemsApp {
162234
egui::CentralPanel::default().show(ctx, |ui| {
163235
match self.sim_type {
164236
SimulationType::TwoD => {
165-
self.viewer_2d.show(ui, &self.simulations_2d[self.sim_2d_index]);
237+
self.viewer_2d.show(ui, &mut self.simulations_2d[self.sim_2d_index]);
166238
}
167239
SimulationType::ThreeD => {
168240
let dt = ui.input(|i| i.stable_dt);

sim-app/src/viewer_2d.rs

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ use sim_core::Simulation2D;
33

44
pub struct Viewer2D {
55
pub needs_update: bool,
6+
pub scale: f32,
7+
pub pan_x: f32,
8+
pub pan_y: f32,
69
texture: Option<egui::TextureHandle>,
710
width: usize,
811
height: usize,
@@ -12,16 +15,19 @@ impl Viewer2D {
1215
pub fn new() -> Self {
1316
Self {
1417
needs_update: true,
18+
scale: 1.0,
19+
pan_x: 0.0,
20+
pan_y: 0.0,
1521
texture: None,
1622
width: 800,
1723
height: 600,
1824
}
1925
}
2026

21-
pub fn show(&mut self, ui: &mut egui::Ui, simulation: &Box<dyn Simulation2D>) {
27+
pub fn show(&mut self, ui: &mut egui::Ui, simulation: &mut Box<dyn Simulation2D>) {
2228
let available_size = ui.available_size();
23-
let width = available_size.x as usize;
24-
let height = available_size.y as usize;
29+
let width = (available_size.x * self.scale) as usize;
30+
let height = (available_size.y * self.scale) as usize;
2531

2632
// Check if we need to recompute
2733
if self.needs_update || width != self.width || height != self.height {
@@ -56,10 +62,32 @@ impl Viewer2D {
5662
self.needs_update = false;
5763
}
5864

59-
// Display texture
65+
// Create an interactive area for the image
6066
if let Some(texture) = &self.texture {
61-
let size = egui::vec2(width as f32, height as f32);
62-
ui.image((texture.id(), size));
67+
let display_size = egui::vec2(available_size.x, available_size.y);
68+
69+
// Create a scrollable area if image is larger than display
70+
let response = ui.allocate_rect(
71+
egui::Rect::from_min_size(ui.cursor().min, display_size),
72+
egui::Sense::click_and_drag(),
73+
);
74+
75+
// Handle dragging for panning
76+
if response.dragged() && simulation.supports_zoom() {
77+
let delta = response.drag_delta();
78+
// Adjust the simulation's center position
79+
simulation.adjust_center(delta.x as f64, delta.y as f64, width, height);
80+
self.needs_update = true;
81+
}
82+
83+
// Draw the image
84+
let rect = response.rect;
85+
ui.painter().image(
86+
texture.id(),
87+
rect,
88+
egui::Rect::from_min_max(egui::pos2(0.0, 0.0), egui::pos2(1.0, 1.0)),
89+
egui::Color32::WHITE,
90+
);
6391
}
6492
}
6593
}

0 commit comments

Comments
 (0)