From bccff1697520245e38f0b5e2ccbac88bd1205bba Mon Sep 17 00:00:00 2001 From: Iris <152874900+basyniae@users.noreply.github.com> Date: Sat, 26 Oct 2024 15:18:34 +0200 Subject: [PATCH] Move update metrics out of app.rs --- src/app.rs | 110 ++++++------------------------ src/app/data_structures/blocks.rs | 46 ++++++++++--- src/app/data_structures/zvec.rs | 2 +- src/app/metrics/boundary_3d.rs | 2 +- src/app/update_metrics.rs | 88 ++++++++++++++++++++++++ 5 files changed, 145 insertions(+), 103 deletions(-) create mode 100644 src/app/update_metrics.rs diff --git a/src/app.rs b/src/app.rs index 0fb8bff..3f340de 100644 --- a/src/app.rs +++ b/src/app.rs @@ -7,19 +7,16 @@ use eframe::emath::Align; use mlua::Lua; use crate::app::data_structures::sampled_parameters::SampledParameters; -use crate::app::math::exact_squircle_bounds::exact_squircle_bounds; -use crate::app::math::square_max::square_max; use crate::app::sampling::{SampleCombineMethod, SampleDistributeMethod}; use crate::app::ui_layer_navigation::ui_layer_navigation; use crate::app::ui_sampling::ui_sampling; use crate::app::ui_viewport::ui_viewport; use crate::app::update_logic::{blocks_update, parameters_update, sampling_points_update}; +use crate::app::update_metrics::update_metrics; use data_structures::blocks::Blocks; use data_structures::layer_config::LayerConfig; use data_structures::zvec::ZVec; use lua_field::LuaField; -use math::convex_hull::get_convex_hull; -use metrics::boundary_3d::boundary_3d; mod colors; mod data_structures; @@ -36,6 +33,7 @@ mod ui_options; mod ui_sampling; mod ui_viewport; mod update_logic; +mod update_metrics; pub struct App { // Layer management @@ -469,95 +467,25 @@ impl eframe::App for App { if self.recompute_metrics { self.recompute_metrics = false; - - // update 2d spatial metrics - self.interior_2d = self - .stack_blocks - .get(self.current_layer) - .unwrap() - .get_interior(); - self.boundary_2d = Blocks::new( - // boundary is in all but not in interior (so all && interior.not()) - self.stack_blocks - .get(self.current_layer) - .unwrap() - .blocks - .iter() - .zip(self.interior_2d.blocks.iter()) - .map(|(all, interior)| *all && !interior) - .collect(), - self.interior_2d.grid_size, - ); - self.complement_2d = self - .stack_blocks - .get(self.current_layer) - .unwrap() - .get_complement(); - - // update 3d spatial metrics - self.boundary_3d = boundary_3d( - &self.stack_blocks, + update_metrics( + self.current_layer, self.layer_lowest, self.layer_highest, - true, - true, - ); - - self.interior_3d = ZVec::new( - (self.layer_lowest..self.layer_highest) - .map(|layer| { - Blocks::new( - self.boundary_3d - .get(layer) - .unwrap() - .blocks - .iter() - .zip(self.stack_blocks.get(layer).unwrap().blocks) - .map(|(is_bdry, is_block)| is_block && !is_bdry) - .collect(), - self.stack_blocks.get(layer).unwrap().grid_size, - ) - }) - .collect(), - self.layer_lowest, - ); - - // update numerical metrics - self.nr_blocks_total = self - .stack_blocks - .get_mut(self.current_layer) - .unwrap() - .get_nr_blocks(); - self.nr_blocks_interior = self.interior_2d.get_nr_blocks(); - self.nr_blocks_boundary = self.boundary_2d.get_nr_blocks(); - - self.outer_corners = self - .stack_blocks - .get_mut(self.current_layer) - .unwrap() - .get_outer_corners(); - self.convex_hull = get_convex_hull(&self.outer_corners); - - self.global_bounding_box = self - .stack_layer_config - .data - .iter() - .map(|g_c| exact_squircle_bounds(g_c, 1.1)) - .fold( - [ - [f64::INFINITY, f64::INFINITY], - [f64::NEG_INFINITY, f64::NEG_INFINITY], - ], - |a, b| square_max(a, b), - ); - - self.global_bounding_box = square_max( - self.global_bounding_box, - exact_squircle_bounds( - &self.stack_layer_config.get(self.current_layer).unwrap(), - 1.1, - ), - ); + self.stack_blocks.get(self.current_layer).unwrap(), + self.stack_blocks.clone(), + self.stack_layer_config.clone(), + &mut self.nr_blocks_total, + &mut self.nr_blocks_interior, + &mut self.nr_blocks_boundary, + &mut self.boundary_2d, + &mut self.interior_2d, + &mut self.complement_2d, + &mut self.boundary_3d, + &mut self.interior_3d, + &mut self.convex_hull, + &mut self.outer_corners, + &mut self.global_bounding_box, + ) } // Status bar (bottom) diff --git a/src/app/data_structures/blocks.rs b/src/app/data_structures/blocks.rs index 4b748c2..442cae1 100644 --- a/src/app/data_structures/blocks.rs +++ b/src/app/data_structures/blocks.rs @@ -15,6 +15,7 @@ pub struct Blocks { // TODO: make intersect and complement methods for easier computation // longterm: Symmetry type detection, then build sequences should be within reach // TODO: make everything use is_block_on_global_coord +/// Getter methods impl Blocks { pub fn new(blocks: Vec, grid_size: usize) -> Self { Blocks { @@ -81,7 +82,10 @@ impl Blocks { output_vec } +} +/// Methods for getting metrics +impl Blocks { /// Get number of blocks pub fn get_nr_blocks(&self) -> u64 { (*self.blocks).into_iter().filter(|b| **b).count() as u64 @@ -90,8 +94,6 @@ impl Blocks { /// Get (thin-walled) interior, i.e., blocks in self which have no neighbors which share a side /// with an air block pub fn get_interior(&self) -> Blocks { - // let mut output_vec = Vec::new(); - Blocks::new( (0..self.grid_size.pow(2)) .map(|i| { @@ -102,10 +104,10 @@ impl Blocks { && i / self.grid_size != 0 && i / self.grid_size != self.grid_size - 1 // cannot lie on the boundary of the grid - && self.blocks[i + 1] == true - && self.blocks[i - 1] == true - && self.blocks[i + self.grid_size] == true - && self.blocks[i - self.grid_size] == true + && self.blocks[i + 1] + && self.blocks[i - 1] + && self.blocks[i + self.grid_size] + && self.blocks[i - self.grid_size] // all direct neighbors should also be blocks }) .collect(), @@ -113,8 +115,32 @@ impl Blocks { ) } - // todo: make direct methods for layer boundary and interior - /// Complement of blocks (for interiors) + /// Get (thin-walled) boundary + /// (There is the obvious relation of boundary + interior = blocks, but we won't use it) + pub fn get_boundary(&self) -> Blocks { + Blocks::new( + (0..self.grid_size.pow(2)) + .map(|i| { + self.blocks[i] == true + // has to be a block + // and (be on the grid boundary or border any non-block) + && ( + i % self.grid_size == 0 + || i % self.grid_size == self.grid_size - 1 + || i / self.grid_size == 0 + || i / self.grid_size == self.grid_size - 1 + || !self.blocks[i + 1] + || !self.blocks[i - 1] + || !self.blocks[i + self.grid_size] + || !self.blocks[i - self.grid_size] + ) + }) + .collect(), + self.grid_size, + ) + } + + /// Complement of blocks (for building interiors) pub fn get_complement(&self) -> Blocks { Blocks::new( (0..self.grid_size.pow(2)) @@ -216,7 +242,7 @@ impl Blocks { // Returns a (unordered) list of all corners of the blocks (so get_block_coords (±0.5,±0.5)) // which are the corner of exactly 1 block (note that exactly 2 blocks corresponds to a corner - // which is an edge of the whole block structure, and exactly 2 blocks correponds to an inner corner) + // which is an edge of the whole block structure, and exactly 2 blocks corresponds to an inner corner) // The convex hull only depends on points of this type (so it should be a large reduction). pub fn get_outer_corners(&self) -> Vec<[f64; 2]> { // loop over all 2x2s in the grid, which we think of as points between the blocks @@ -224,7 +250,7 @@ impl Blocks { let mut output = vec![]; - // For an n×n grid there are (n-1)×(n-1) points inbetween 4 points... (vaguely speaking) + // For an n×n grid there are (n-1)×(n-1) points between 4 points... (vaguely speaking) for corner_point in 0..self.grid_size.pow(2) { // Filter out those corner points which don't have a 2×2 around them // (using bottom right index to match corners to their block) diff --git a/src/app/data_structures/zvec.rs b/src/app/data_structures/zvec.rs index 6514e55..3e92e47 100644 --- a/src/app/data_structures/zvec.rs +++ b/src/app/data_structures/zvec.rs @@ -2,7 +2,7 @@ use std::collections::VecDeque; use std::fmt::Debug; /// Vector whose index is a continuous interval of the integers (Z) -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct ZVec { pub data: VecDeque, minimum: isize, diff --git a/src/app/metrics/boundary_3d.rs b/src/app/metrics/boundary_3d.rs index e0858a5..6a54d28 100644 --- a/src/app/metrics/boundary_3d.rs +++ b/src/app/metrics/boundary_3d.rs @@ -32,7 +32,7 @@ pub fn boundary_3d( || !blocks.blocks[i - 1] || !blocks.blocks[i + blocks.grid_size] || !blocks.blocks[i - blocks.grid_size] - // top and bottom faces of stack: ( + // top and bottom faces of stack: || (layer == layer_min && floating_bottom) || (layer == layer_max && floating_top) // vertical boundary: see if 1. the layer above exists, 2. there is no block at the global coords on the layer above diff --git a/src/app/update_metrics.rs b/src/app/update_metrics.rs new file mode 100644 index 0000000..cda15cf --- /dev/null +++ b/src/app/update_metrics.rs @@ -0,0 +1,88 @@ +use crate::app; +use crate::app::data_structures::blocks::Blocks; +use crate::app::data_structures::layer_config::LayerConfig; +use crate::app::data_structures::zvec::ZVec; +use crate::app::math::exact_squircle_bounds::exact_squircle_bounds; +use crate::app::math::square_max::square_max; + +pub fn update_metrics( + current_layer: isize, + layer_lowest: isize, + layer_highest: isize, + current_layer_blocks: Blocks, + stack_blocks: ZVec, + stack_layer_config: ZVec, + + // Metrics + nr_blocks_total: &mut u64, + nr_blocks_interior: &mut u64, + nr_blocks_boundary: &mut u64, + boundary_2d: &mut Blocks, + interior_2d: &mut Blocks, + complement_2d: &mut Blocks, + boundary_3d: &mut ZVec, + interior_3d: &mut ZVec, + convex_hull: &mut Vec<[f64; 2]>, + outer_corners: &mut Vec<[f64; 2]>, + + global_bounding_box: &mut [[f64; 2]; 2], +) { + // update 2d spatial metrics + *interior_2d = current_layer_blocks.get_interior(); + *boundary_2d = current_layer_blocks.get_boundary(); + *complement_2d = current_layer_blocks.get_complement(); + + // update 3d spatial metrics + *boundary_3d = app::metrics::boundary_3d::boundary_3d( + &stack_blocks, + layer_lowest, + layer_highest, + true, + true, + ); + + // todo: move computation to boundary_3d.rs + *interior_3d = ZVec::new( + (layer_lowest..layer_highest) + .map(|layer| { + Blocks::new( + boundary_3d + .get(layer) + .unwrap() + .blocks + .iter() + .zip(stack_blocks.get(layer).unwrap().blocks) + .map(|(is_bdry, is_block)| is_block && !is_bdry) + .collect(), + stack_blocks.get(layer).unwrap().grid_size, + ) + }) + .collect(), + layer_lowest, + ); + + // update numerical metrics + *nr_blocks_total = current_layer_blocks.get_nr_blocks(); + *nr_blocks_interior = interior_2d.get_nr_blocks(); + *nr_blocks_boundary = boundary_2d.get_nr_blocks(); + + *outer_corners = current_layer_blocks.get_outer_corners(); + *convex_hull = app::math::convex_hull::get_convex_hull(&outer_corners); + + *global_bounding_box = stack_layer_config + .data + .iter() + .map(|g_c| exact_squircle_bounds(g_c, 1.1)) + .fold( + [ + [f64::INFINITY, f64::INFINITY], + [f64::NEG_INFINITY, f64::NEG_INFINITY], + ], + |a, b| square_max(a, b), + ); + + *global_bounding_box = square_max( + *global_bounding_box, + exact_squircle_bounds(&stack_layer_config.get(current_layer).unwrap(), 1.1), + ); +}