From 0c8c9e4150e55032391c02cdbb0c3c914dfa1e21 Mon Sep 17 00:00:00 2001 From: Jeroen Gardeyn Date: Wed, 7 Feb 2024 20:01:45 +0100 Subject: [PATCH] more polishing & documentation --- jaguars/src/collision_detection/cd_engine.rs | 61 +++++++++-------- .../haz_prox_grid/boundary_fill.rs | 18 +++-- .../haz_prox_grid/circling_iterator.rs | 2 + .../collision_detection/haz_prox_grid/grid.rs | 23 ++++--- .../haz_prox_grid/grid_generator.rs | 15 ++--- .../haz_prox_grid/hazard_proximity_grid.rs | 10 +-- .../haz_prox_grid/hpg_cell.rs | 6 +- jaguars/src/collision_detection/hazard.rs | 9 ++- .../hazard_filters/bin_haz_filter.rs | 11 +-- .../hazard_filters/combo_haz_filter.rs | 6 +- .../hazard_filters/entity_haz_filter.rs | 5 +- .../hazard_filters/hazard_filter.rs | 18 +++-- .../hazard_filters/qz_haz_filter.rs | 10 +-- jaguars/src/collision_detection/mod.rs | 1 - .../collision_detection/quadtree/qt_hazard.rs | 26 +++---- .../quadtree/qt_hazard_vec.rs | 38 ++++++----- .../collision_detection/quadtree/qt_node.rs | 22 +++--- .../quadtree/qt_partial_hazard.rs | 4 +- jaguars/src/entities/bin.rs | 3 - jaguars/src/entities/item.rs | 2 +- jaguars/src/entities/problems/sp_problem.rs | 2 +- jaguars/src/entities/solution.rs | 1 + .../src/geometry/fail_fast/sp_surrogate.rs | 4 +- jaguars/src/geometry/geo_traits.rs | 4 +- .../src/geometry/primitives/aa_rectangle.rs | 67 +++++++++---------- jaguars/src/geometry/primitives/circle.rs | 4 +- jaguars/src/util/assertions.rs | 10 +-- jaguars/src/util/f64a.rs | 3 +- lbf/benches/fast_fail_bench.rs | 2 +- lbf/src/io/svg_export.rs | 12 ++-- lbf/src/lbf_optimizer.rs | 2 +- 31 files changed, 215 insertions(+), 186 deletions(-) diff --git a/jaguars/src/collision_detection/cd_engine.rs b/jaguars/src/collision_detection/cd_engine.rs index 418d908..76292cf 100644 --- a/jaguars/src/collision_detection/cd_engine.rs +++ b/jaguars/src/collision_detection/cd_engine.rs @@ -20,6 +20,10 @@ use crate::geometry::transformation::Transformation; use crate::util::assertions; use crate::util::config::{CDEConfig, HazProxConfig, QuadTreeConfig}; + +/// The Collision Detection Engine (CDE) is responsible for validating potential placements of items in a Layout. +/// It can be queried to check if a given shape or surrogate collides with any hazards in the layout. +/// It is updated by the Layout, when its state changes. #[derive(Clone, Debug)] pub struct CDEngine { quadtree: QTNode, @@ -31,6 +35,15 @@ pub struct CDEngine { uncommited_deregisters: Vec, } + +/// Snapshot of the state of CDE at a given time. +/// The CDE can take snapshots of itself at any time, and use them to restore to that state later. +#[derive(Clone, Debug)] +pub struct CDESnapshot { + dynamic_hazards: Vec, + grid: Option> +} + impl CDEngine { pub fn new(bbox: AARectangle, static_hazards: Vec, config: CDEConfig) -> CDEngine { let qt_depth = match config.quadtree { @@ -217,27 +230,27 @@ impl CDEngine { } //QUERY ---------------------------------------------------------------------------------------- - pub fn shape_collides(&self, shape: &SimplePolygon, ignored_entities: &[HazardEntity]) -> bool { + pub fn shape_collides(&self, shape: &SimplePolygon, irrelevant_hazards: &[HazardEntity]) -> bool { match self.bbox.relation_to(&shape.bbox()) { //Not fully inside bbox => definite collision GeoRelation::Disjoint | GeoRelation::Enclosed | GeoRelation::Intersecting => true, GeoRelation::Surrounding => { - self.collision_by_edge_intersection(shape, ignored_entities) || - self.collision_by_containment(shape, ignored_entities) + self.collision_by_edge_intersection(shape, irrelevant_hazards) || + self.collision_by_containment(shape, irrelevant_hazards) } } } - pub fn surrogate_collides(&self, base_surrogate: &SPSurrogate, transform: &Transformation, ignored_entities: &[HazardEntity]) -> bool { + pub fn surrogate_collides(&self, base_surrogate: &SPSurrogate, transform: &Transformation, irrelevant_hazards: &[HazardEntity]) -> bool { for pole in base_surrogate.ff_poles() { let t_pole = pole.transform_clone(transform); - if self.quadtree.collides(&t_pole, ignored_entities).is_some() { + if self.quadtree.collides(&t_pole, irrelevant_hazards).is_some() { return true; } } for pier in base_surrogate.ff_piers() { let t_pier = pier.transform_clone(transform); - if self.quadtree.collides(&t_pier, ignored_entities).is_some() { + if self.quadtree.collides(&t_pier, irrelevant_hazards).is_some() { return true; } } @@ -251,35 +264,35 @@ impl CDEngine { } } - pub fn edge_definitely_collides(&self, edge: &Edge, ignored_entities: &[HazardEntity]) -> Tribool { + pub fn edge_definitely_collides(&self, edge: &Edge, irrelevant_hazards: &[HazardEntity]) -> Tribool { match !self.bbox.collides_with(&edge.start()) || !self.bbox.collides_with(&edge.end()) { true => Tribool::True, //if either the start or end of the edge is outside the quadtree, it definitely collides - false => self.quadtree.definitely_collides(edge, ignored_entities) + false => self.quadtree.definitely_collides(edge, irrelevant_hazards) } } - pub fn circle_definitely_collides(&self, circle: &Circle, ignored_entities: &[HazardEntity]) -> Tribool { + pub fn circle_definitely_collides(&self, circle: &Circle, irrelevant_hazards: &[HazardEntity]) -> Tribool { match self.bbox.collides_with(&circle.center) { false => Tribool::True, //outside the quadtree, so definitely collides - true => self.quadtree.definitely_collides(circle, ignored_entities) + true => self.quadtree.definitely_collides(circle, irrelevant_hazards) } } - pub fn entities_in_circle(&self, circle: &Circle, ignored_entities: &[HazardEntity]) -> Vec { + pub fn entities_in_circle(&self, circle: &Circle, irrelevant_hazards: &[HazardEntity]) -> Vec { let mut colliding_entities = vec![]; - let mut ignored_entities = ignored_entities.iter().cloned().collect_vec(); + let mut irrelevant_hazards = irrelevant_hazards.iter().cloned().collect_vec(); //Keep testing the quadtree for intersections until no (non-ignored) entities collide - while let Some(haz_entity) = self.quadtree.collides(circle, &ignored_entities) { + while let Some(haz_entity) = self.quadtree.collides(circle, &irrelevant_hazards) { colliding_entities.push(haz_entity.clone()); - ignored_entities.push(haz_entity.clone()); + irrelevant_hazards.push(haz_entity.clone()); } let circle_center_in_qt = self.bbox.collides_with(&circle.center); if !circle_center_in_qt && colliding_entities.is_empty() { // The circle center is outside the quadtree - if !ignored_entities.contains(&&HazardEntity::BinExterior) { + if !irrelevant_hazards.contains(&&HazardEntity::BinExterior) { //Add the bin as a hazard, unless it is ignored colliding_entities.push(HazardEntity::BinExterior); } @@ -288,16 +301,16 @@ impl CDEngine { colliding_entities } - fn collision_by_edge_intersection(&self, shape: &SimplePolygon, ignored_entities: &[HazardEntity]) -> bool { + fn collision_by_edge_intersection(&self, shape: &SimplePolygon, irrelevant_hazards: &[HazardEntity]) -> bool { shape.edge_iter() - .any(|e| self.quadtree.collides(&e, ignored_entities).is_some()) + .any(|e| self.quadtree.collides(&e, irrelevant_hazards).is_some()) } - fn collision_by_containment(&self, shape: &SimplePolygon, ignored_entities: &[HazardEntity]) -> bool + fn collision_by_containment(&self, shape: &SimplePolygon, irrelevant_hazards: &[HazardEntity]) -> bool { - //collect all active and non-ignored hazard_filters + //collect all active and non-ignored hazards let mut relevant_hazards = self.all_hazards() - .filter(|h| h.active && !ignored_entities.contains(&h.entity)); + .filter(|h| h.active && !irrelevant_hazards.contains(&h.entity)); relevant_hazards.any(|haz| { //Due to possible fp issues, we check if the bboxes are "almost" related @@ -334,12 +347,4 @@ impl CDEngine { } }) } -} - -//Snapshot of the CDE state at a given time. -//Can be used to restore the CDE to a previous state. -#[derive(Clone, Debug)] -pub struct CDESnapshot { - dynamic_hazards: Vec, - grid: Option> } \ No newline at end of file diff --git a/jaguars/src/collision_detection/haz_prox_grid/boundary_fill.rs b/jaguars/src/collision_detection/haz_prox_grid/boundary_fill.rs index 1cc6c21..e7a81aa 100644 --- a/jaguars/src/collision_detection/haz_prox_grid/boundary_fill.rs +++ b/jaguars/src/collision_detection/haz_prox_grid/boundary_fill.rs @@ -4,11 +4,11 @@ use crate::collision_detection::haz_prox_grid::circling_iterator::CirclingIterat use crate::collision_detection::haz_prox_grid::grid::Grid; use crate::geometry::primitives::aa_rectangle::AARectangle; -//Boundary Fill algorithm -//1. Queue all cells within the seed bounding box -//2. Visit the cells in the queue, once a seed is found, dequeue all cells and queue all its neighbors -//3. Explore and queue unvisited neighbors until queue is empty - +///Boundary Fill type of algorithm. +///Iteratively visits cells within a grid. +///While unseeded, the struct will visit cells from the seed_bbox, from the inside out. +///When a cell's neighbors are queued, the struct is considered seeded, and will from then on visit cells from the queue. +///The "Fill" finished when there are no more cells to visit, i.e. the seed_iterator runs out (unseeded) or the queue is empty (seeded) #[derive(Debug, Clone)] pub struct BoundaryFillGrid { state: Vec, @@ -19,7 +19,9 @@ pub struct BoundaryFillGrid { } impl BoundaryFillGrid { - pub fn new(seed_bbox: AARectangle, grid: &Grid) -> Self { + + /// Creates a new BoundaryFillGrid, add all cells inside the seed_bbox to the queue + pub fn new(grid: &Grid, seed_bbox: AARectangle) -> Self { let state = vec![CellState::new(); grid.n_rows() * grid.n_cols()]; //Find the range of rows and columns which reside inside the seed_bbox @@ -41,6 +43,8 @@ impl BoundaryFillGrid { } } + /// Returns the next cell to visit and pops it from the queue, + /// if there are no more cells to visit return None pub fn pop(&mut self, grid: &Grid) -> Option { match self.seeded { false => { @@ -69,6 +73,8 @@ impl BoundaryFillGrid { } } + /// Adds all unvisited neighbors of the cell at index to the queue + /// Also marks the grid as seeded pub fn queue_neighbors(&mut self, index: usize, grid: &Grid) { self.seeded = true; diff --git a/jaguars/src/collision_detection/haz_prox_grid/circling_iterator.rs b/jaguars/src/collision_detection/haz_prox_grid/circling_iterator.rs index 918ccff..a9279fd 100644 --- a/jaguars/src/collision_detection/haz_prox_grid/circling_iterator.rs +++ b/jaguars/src/collision_detection/haz_prox_grid/circling_iterator.rs @@ -2,6 +2,8 @@ use std::ops::RangeInclusive; use crate::collision_detection::haz_prox_grid::outward_iterator::OutwardIterator; +/// 2D version of OutwardIterator +/// Iterates over a 2D range from the center outwards #[derive(Debug, Clone)] pub struct CirclingIterator { original_col_iter: OutwardIterator, diff --git a/jaguars/src/collision_detection/haz_prox_grid/grid.rs b/jaguars/src/collision_detection/haz_prox_grid/grid.rs index 38713fd..0d0e68b 100644 --- a/jaguars/src/collision_detection/haz_prox_grid/grid.rs +++ b/jaguars/src/collision_detection/haz_prox_grid/grid.rs @@ -3,10 +3,10 @@ use std::ops::RangeInclusive; use itertools::Itertools; use ordered_float::NotNan; +use crate::geometry::primitives::point::Point; -//abstract representation of a grid of elements at specific coordinates -//divided into rows and columns - +/// Representation of a grid of optional elements of type T +/// Divided into rows and columns, where each row and column has a unique coordinate #[derive(Clone, Debug)] pub struct Grid { cells: Vec>, @@ -17,14 +17,16 @@ pub struct Grid { } impl Grid { - pub fn new(elements: Vec<(T, (f64, f64))>) -> Self { + + /// Creates a new grid from a vector of values of type T and their coordinates + pub fn new(elements: Vec<(T, Point)>) -> Self { //find all unique rows and columns from the element's coordinates let rows = elements.iter() - .map(|(_e, (_x, y))| NotNan::new(*y).unwrap()) + .map(|(_e, Point(_x, y))| NotNan::new(*y).unwrap()) .unique().sorted().collect::>>(); let cols = elements.iter() - .map(|(_e, (x, _y))| NotNan::new(*x).unwrap()) + .map(|(_e, Point(x, _y))| NotNan::new(*x).unwrap()) .unique().sorted().collect::>>(); let n_rows = rows.len(); @@ -33,7 +35,7 @@ impl Grid { //create a vector of cells, with the correct size let mut cells = (0..n_rows * n_cols).map(|_| None).collect_vec(); - for (element, (x, y)) in elements { + for (element, Point(x, y)) in elements { //search correct row and col for the cell let row = match rows.binary_search(&NotNan::new(y).unwrap()) { Ok(row) => row, @@ -91,13 +93,14 @@ impl Grid { start_col..=end_col } + ///Returns the indices of the 8 directly neighboring cells. + ///If the cell is on the edge, the index of the cell itself is returned instead for neighbors out of bounds pub fn get_neighbors(&self, idx: usize) -> [usize; 8] { - //returns the indices of the 8 directly neighboring cells. If the cell is on the edge, the index of the cell itself is returned let mut neighbors = [0; 8]; let (row, col) = (idx / self.n_cols, idx % self.n_cols); let (n_cols, n_rows) = (self.n_cols, self.n_rows); - //ugly but fast + //ugly, but seems to be the fastest way of doing it neighbors[0] = if row > 0 && col > 0 { idx - n_cols - 1 } else { idx }; neighbors[1] = if row > 0 { idx - n_cols } else { idx }; neighbors[2] = if row > 0 && col < n_cols - 1 { idx - n_cols + 1 } else { idx }; @@ -116,7 +119,7 @@ impl Grid { fn calculate_index(row: usize, col: usize, n_rows: usize, n_cols: usize) -> Option { match (row.cmp(&n_rows), col.cmp(&n_cols)) { - (Ordering::Less, Ordering::Less) => Some(row * n_cols + col), //out of bounds + (Ordering::Less, Ordering::Less) => Some(row * n_cols + col), _ => None //out of bounds } } diff --git a/jaguars/src/collision_detection/haz_prox_grid/grid_generator.rs b/jaguars/src/collision_detection/haz_prox_grid/grid_generator.rs index 2a2adff..7e0c9b3 100644 --- a/jaguars/src/collision_detection/haz_prox_grid/grid_generator.rs +++ b/jaguars/src/collision_detection/haz_prox_grid/grid_generator.rs @@ -6,9 +6,9 @@ use crate::geometry::geo_traits::{DistanceFrom, Shape}; use crate::geometry::primitives::aa_rectangle::AARectangle; use crate::geometry::primitives::point::Point; +/// Generates a grid of equal sized square rectangles within a shape. +/// The number of cells is approximately equal to target_n_cells, but can be slightly more or less pub fn generate(bbox: AARectangle, hazards: &[Hazard], target_n_cells: usize) -> Vec { - //generates a grid of equal sized square cells in the shape. - //the number of cells is approximately equal to target_n_cells, but can be slightly more or less assert!(bbox.area() > 0.0, "bbox has zero area"); let mut cells = vec![]; @@ -39,7 +39,7 @@ pub fn generate(bbox: AARectangle, hazards: &[Hazard], target_n_cells: usize) -> } } if n_iters >= 25 { - debug!("grid generation is taking too long, aborting after 25 iterations ({} cells instead of target {})", cells.len(), target_n_cells); + debug!("grid generation is taking too long, stopping after 25 iterations ({} cells instead of target {})", cells.len(), target_n_cells); break; } @@ -51,15 +51,14 @@ pub fn generate(bbox: AARectangle, hazards: &[Hazard], target_n_cells: usize) -> } match attempt { - Ordering::Equal => { - //just right - break; - } + //Close enough + Ordering::Equal => break, + //not enough cells, decrease their size Ordering::Less => { - //not enough cells, decrease their size correction_factor -= step_size; cells.clear(); } + //too many cells, increase their size Ordering::Greater => { correction_factor += step_size; cells.clear(); diff --git a/jaguars/src/collision_detection/haz_prox_grid/hazard_proximity_grid.rs b/jaguars/src/collision_detection/haz_prox_grid/hazard_proximity_grid.rs index 728ee71..17c5e65 100644 --- a/jaguars/src/collision_detection/haz_prox_grid/hazard_proximity_grid.rs +++ b/jaguars/src/collision_detection/haz_prox_grid/hazard_proximity_grid.rs @@ -28,9 +28,10 @@ impl HazardProximityGrid { let elements = cells.into_iter() .map(|bbox| HPGCell::new(bbox, static_hazards)) .map(|cell| { - let centroid = cell.centroid(); - (cell, centroid.into()) - }).collect_vec(); + let pos = cell.centroid(); + (cell, pos) + }) + .collect_vec(); Grid::new(elements) }; @@ -58,7 +59,7 @@ impl HazardProximityGrid { ) }; - let mut b_fill = BoundaryFillGrid::new(seed_bbox, &self.grid); + let mut b_fill = BoundaryFillGrid::new(&self.grid, seed_bbox); while let Some(next_dot_index) = b_fill.pop(&self.grid) { let cell = self.grid.elements_mut()[next_dot_index].as_mut(); @@ -75,6 +76,7 @@ impl HazardProximityGrid { } } + //TODO: move this to an assertion check debug_assert!( { let old_cells = self.grid.elements().clone(); diff --git a/jaguars/src/collision_detection/haz_prox_grid/hpg_cell.rs b/jaguars/src/collision_detection/haz_prox_grid/hpg_cell.rs index 2610783..e9dd333 100644 --- a/jaguars/src/collision_detection/haz_prox_grid/hpg_cell.rs +++ b/jaguars/src/collision_detection/haz_prox_grid/hpg_cell.rs @@ -13,6 +13,8 @@ use crate::geometry::primitives::circle::Circle; use crate::geometry::primitives::point::Point; use crate::N_QUALITIES; + +/// Represents a cell in the Hazard Proximity Grid #[derive(Clone, Debug)] pub struct HPGCell { bbox: AARectangle, @@ -20,7 +22,7 @@ pub struct HPGCell { radius: f64, ///Proximity of closest hazard which is universally applicable (bin or item) uni_haz_prox: (Proximity, HazardEntity), - ///Proximity of universal static hazard_filters + ///Proximity of universal static hazards static_uni_haz_prox: (Proximity, HazardEntity), ///proximity of closest quality zone for each quality qz_haz_prox: [Proximity; N_QUALITIES], @@ -115,7 +117,7 @@ impl HPGCell { pub fn register_hazard(&mut self, to_register: &Hazard) -> HPGCellUpdate { let current_prox = self.universal_hazard_proximity().0; - //For dynamic hazard_filters, the surrogate poles are used to calculate the distance to the hazard (overestimation, but fast) + //For dynamic hazards, the surrogate poles are used to calculate the distance to the hazard (overestimation, but fast) let haz_prox = match to_register.entity.position() { GeoPosition::Interior => distance_to_surrogate_poles_border(self, &to_register.shape.surrogate().poles), GeoPosition::Exterior => unreachable!("No implementation yet for dynamic exterior hazards") diff --git a/jaguars/src/collision_detection/hazard.rs b/jaguars/src/collision_detection/hazard.rs index 611937d..69147f1 100644 --- a/jaguars/src/collision_detection/hazard.rs +++ b/jaguars/src/collision_detection/hazard.rs @@ -4,10 +4,15 @@ use crate::entities::placed_item::PlacedItemUID; use crate::geometry::geo_enums::GeoPosition; use crate::geometry::primitives::simple_polygon::SimplePolygon; +/// Defines a certain spatial constraint that affects the feasibility of placed items +/// Hazards are defined by a certain entity, have a shape and can be active or inactive #[derive(Clone, Debug)] pub struct Hazard { + /// The entity inducing the hazard pub entity: HazardEntity, + /// The shape of the hazard pub shape: Arc, + /// Whether the hazard is currently active or not pub active: bool, } @@ -32,7 +37,7 @@ pub enum HazardEntity { impl HazardEntity { - /// Returns whether the entity induces an Interior or Exterior hazard + /// Whether the entity induces an Interior or Exterior hazard pub fn position(&self) -> GeoPosition { match self { HazardEntity::PlacedItem(_) => GeoPosition::Interior, @@ -42,7 +47,7 @@ impl HazardEntity { } } - /// Returns true if the hazard is dynamic in nature, i.e. it can be modified by the optimizer + /// True if the hazard is dynamic in nature, i.e. it can be modified by the optimizer pub fn dynamic(&self) -> bool { match self { HazardEntity::PlacedItem(_) => true, diff --git a/jaguars/src/collision_detection/hazard_filters/bin_haz_filter.rs b/jaguars/src/collision_detection/hazard_filters/bin_haz_filter.rs index 7c403f9..86e54aa 100644 --- a/jaguars/src/collision_detection/hazard_filters/bin_haz_filter.rs +++ b/jaguars/src/collision_detection/hazard_filters/bin_haz_filter.rs @@ -1,16 +1,17 @@ use crate::collision_detection::hazard_filters::hazard_filter::HazardFilter; use crate::collision_detection::hazard::HazardEntity; +/// Filter that deems all hazards induced by the Bin as irrelevant #[derive(Clone)] pub struct BinHazardFilter; impl HazardFilter for BinHazardFilter { - fn is_relevant(&self, entity: &HazardEntity) -> bool { + fn is_irrelevant(&self, entity: &HazardEntity) -> bool { match entity { - HazardEntity::PlacedItem(_) => true, - HazardEntity::BinExterior => false, - HazardEntity::BinHole { .. } => false, - HazardEntity::QualityZoneInferior { .. } => false, + HazardEntity::PlacedItem(_) => false, + HazardEntity::BinExterior => true, + HazardEntity::BinHole { .. } => true, + HazardEntity::QualityZoneInferior { .. } => true, } } } diff --git a/jaguars/src/collision_detection/hazard_filters/combo_haz_filter.rs b/jaguars/src/collision_detection/hazard_filters/combo_haz_filter.rs index 3a6b3d0..7f05452 100644 --- a/jaguars/src/collision_detection/hazard_filters/combo_haz_filter.rs +++ b/jaguars/src/collision_detection/hazard_filters/combo_haz_filter.rs @@ -1,13 +1,15 @@ use crate::collision_detection::hazard_filters::hazard_filter::HazardFilter; use crate::collision_detection::hazard::HazardEntity; +/// A filter that combines multiple hazard filters into one pub struct CombinedHazardFilter<'a> { pub filters: Vec>, } impl<'a> HazardFilter for CombinedHazardFilter<'a> { - fn is_relevant(&self, entity: &HazardEntity) -> bool { - self.filters.iter().all(|f| f.is_relevant(entity)) + fn is_irrelevant(&self, entity: &HazardEntity) -> bool { + self.filters.iter() + .any(|f| f.is_irrelevant(entity)) } } diff --git a/jaguars/src/collision_detection/hazard_filters/entity_haz_filter.rs b/jaguars/src/collision_detection/hazard_filters/entity_haz_filter.rs index 49dc6bc..5b1d4ec 100644 --- a/jaguars/src/collision_detection/hazard_filters/entity_haz_filter.rs +++ b/jaguars/src/collision_detection/hazard_filters/entity_haz_filter.rs @@ -1,14 +1,15 @@ use crate::collision_detection::hazard_filters::hazard_filter::HazardFilter; use crate::collision_detection::hazard::HazardEntity; +/// A filter that deems hazards induced by specific entities as irrelevant pub struct EntityHazardFilter { entities: Vec, } impl HazardFilter for EntityHazardFilter { - fn is_relevant(&self, entity: &HazardEntity) -> bool { - !self.entities.contains(entity) + fn is_irrelevant(&self, entity: &HazardEntity) -> bool { + self.entities.contains(entity) } } diff --git a/jaguars/src/collision_detection/hazard_filters/hazard_filter.rs b/jaguars/src/collision_detection/hazard_filters/hazard_filter.rs index 3921a0b..221c5b3 100644 --- a/jaguars/src/collision_detection/hazard_filters/hazard_filter.rs +++ b/jaguars/src/collision_detection/hazard_filters/hazard_filter.rs @@ -3,13 +3,19 @@ use itertools::Itertools; use crate::collision_detection::hazard::Hazard; use crate::collision_detection::hazard::HazardEntity; + +/// A filter that determines which hazards are relevant for a specific purpose pub trait HazardFilter { - fn is_relevant(&self, entity: &HazardEntity) -> bool; + fn is_irrelevant(&self, entity: &HazardEntity) -> bool; } -pub fn ignored_entities<'a>(filter: &impl HazardFilter, hazards: impl Iterator) -> Vec { - hazards - .filter(|h| !filter.is_relevant(&h.entity)) - .map(|h| h.entity.clone()) - .collect_vec() + +/// Returns the HazardEntities that are deemed irrelevant the given filter +pub fn get_irrelevant_hazard_entities<'a>(filter: &impl HazardFilter, hazards: impl Iterator) -> Vec { + hazards.filter_map(|h| { + match filter.is_irrelevant(&h.entity){ + true => Some(h.entity.clone()), + false => None + } + }).collect_vec() } \ No newline at end of file diff --git a/jaguars/src/collision_detection/hazard_filters/qz_haz_filter.rs b/jaguars/src/collision_detection/hazard_filters/qz_haz_filter.rs index 2fe9d11..c15bb0e 100644 --- a/jaguars/src/collision_detection/hazard_filters/qz_haz_filter.rs +++ b/jaguars/src/collision_detection/hazard_filters/qz_haz_filter.rs @@ -1,16 +1,18 @@ use crate::collision_detection::hazard_filters::hazard_filter::HazardFilter; use crate::collision_detection::hazard::HazardEntity; + +/// A filter that deems hazards induced by quality zones above a certain quality as irrelevant #[derive(Clone, Debug)] pub struct QZHazardFilter { - pub base_quality: usize, + pub cutoff_quality: usize, } impl HazardFilter for QZHazardFilter { - fn is_relevant(&self, entity: &HazardEntity) -> bool { + fn is_irrelevant(&self, entity: &HazardEntity) -> bool { match entity { - HazardEntity::QualityZoneInferior { quality, .. } => *quality < self.base_quality, - _ => true, + HazardEntity::QualityZoneInferior { quality, .. } => *quality >= self.cutoff_quality, + _ => false, } } } \ No newline at end of file diff --git a/jaguars/src/collision_detection/mod.rs b/jaguars/src/collision_detection/mod.rs index a653f5f..373daa2 100644 --- a/jaguars/src/collision_detection/mod.rs +++ b/jaguars/src/collision_detection/mod.rs @@ -2,5 +2,4 @@ pub mod cd_engine; pub mod quadtree; pub mod haz_prox_grid; pub mod hazard_filters; - pub mod hazard; diff --git a/jaguars/src/collision_detection/quadtree/qt_hazard.rs b/jaguars/src/collision_detection/quadtree/qt_hazard.rs index cd5e091..4c25950 100644 --- a/jaguars/src/collision_detection/quadtree/qt_hazard.rs +++ b/jaguars/src/collision_detection/quadtree/qt_hazard.rs @@ -1,5 +1,4 @@ use std::borrow::Borrow; -use std::cmp::Ordering; use crate::collision_detection::hazard::Hazard; use crate::collision_detection::hazard::HazardEntity; use crate::collision_detection::quadtree::qt_partial_hazard::{EdgeIndices, QTPartialHazard}; @@ -7,7 +6,7 @@ use crate::geometry::geo_enums::{GeoPosition, GeoRelation}; use crate::geometry::geo_traits::{CollidesWith, Shape}; use crate::geometry::primitives::aa_rectangle::AARectangle; -//Hazards in a QTNode +/// Represents the manifestation of a hazard in a QTNode #[derive(Clone, Debug)] pub struct QTHazard { pub entity: HazardEntity, @@ -15,6 +14,14 @@ pub struct QTHazard { pub active: bool, } +#[derive(Clone, Debug)] +pub enum QTHazPresence { + None, + Partial(QTPartialHazard), + Entire +} + + impl From for QTHazard where T: Borrow { fn from(hazard: T) -> Self { Self { @@ -100,7 +107,7 @@ impl QTHazard { //check if a neighbor is already resolved // Because nodes with Entire and None are never neighboring (they are always separated by a node with Partial), // if a neighbor is either Entire or None, this quadrant is also Entire or None - let [n_0, n_1] = CHILD_NEIGHBORS[i]; + let [n_0, n_1] = AARectangle::QUADRANT_NEIGHBOR_LAYOUT[i]; constricted_presence[i] = match (&constricted_presence[n_0], &constricted_presence[n_1]) { (Some(QTHazPresence::Entire), _) | (_, Some(QTHazPresence::Entire)) => { Some(QTHazPresence::Entire) @@ -135,19 +142,6 @@ impl QTHazard { } } -// QTNode children array layout: -// 0 | 1 -// ----- -// 2 | 3 -const CHILD_NEIGHBORS: [[usize; 2]; 4] = [[1, 2], [0, 3], [0, 3], [1, 2]]; - -#[derive(Clone, Debug)] -pub enum QTHazPresence { - None, - Partial(QTPartialHazard), - Entire -} - impl Into for &QTHazPresence { fn into(self) -> u8 { match self { diff --git a/jaguars/src/collision_detection/quadtree/qt_hazard_vec.rs b/jaguars/src/collision_detection/quadtree/qt_hazard_vec.rs index 639c3d4..86919d5 100644 --- a/jaguars/src/collision_detection/quadtree/qt_hazard_vec.rs +++ b/jaguars/src/collision_detection/quadtree/qt_hazard_vec.rs @@ -5,10 +5,11 @@ use crate::collision_detection::quadtree::qt_hazard::QTHazard; use crate::collision_detection::quadtree::qt_hazard::QTHazPresence; /// Vector of QTHazards, which always remains sorted by active, presence. -/// This is a performance optimization to be able to quickly return the strongest hazard +/// This is a performance optimization to be able to quickly return the "strongest" hazard +/// Strongest meaning the first active hazard with the highest presence (Entire > Partial > None) #[derive(Clone, Debug)] pub struct QTHazardVec { - /// sorted by active, presence + /// Sorted in descending order by strongest hazards: Vec, n_active: usize, } @@ -23,7 +24,7 @@ impl QTHazardVec { pub fn add(&mut self, haz: QTHazard) { debug_assert!(self.hazards.iter().filter(|other| other.entity == haz.entity && matches!(haz.entity, HazardEntity::PlacedItem(_))).count() == 0, "More than one hazard from same item entity in the vector! (This should never happen!)"); - match self.hazards.binary_search_by(|probe| QTHazardVec::order_stronger(probe, &haz)) { + match self.hazards.binary_search_by(|probe| order_by_descending_strength(probe, &haz)) { Ok(pos) | Err(pos) => { self.n_active += haz.active as usize; self.hazards.insert(pos, haz); @@ -46,13 +47,16 @@ impl QTHazardVec { } #[inline(always)] - pub fn strongest(&self, ignored_entities: &[HazardEntity]) -> Option<&QTHazard> { + pub fn strongest(&self, irrelevant_hazards: &[HazardEntity]) -> Option<&QTHazard> { debug_assert!(self.hazards.iter().filter(|hz| hz.active).count() == self.n_active, "Active hazards count is not correct!"); - debug_assert!(self.hazards.windows(2).all(|w| QTHazardVec::order_stronger(&w[0], &w[1]) != Ordering::Greater), "Hazards are not sorted correctly!"); - match (self.n_active, ignored_entities) { - (0, _) => None, //no active hazards - (_, []) => Some(&self.hazards[0]), //no ignored entities and at least one active hazard - (_, _) => self.hazards[0..self.n_active].iter().find(|hz| !ignored_entities.contains(&hz.entity)), //at least one active hazard and some ignored entities + debug_assert!(self.hazards.windows(2).all(|w| order_by_descending_strength(&w[0], &w[1]) != Ordering::Greater), "Hazards are not sorted correctly!"); + match (self.n_active, irrelevant_hazards) { + //no active hazards + (0, _) => None, + //no ignored entities + (_, []) => Some(&self.hazards[0]), + //Some ignored entities + (_, _) => self.hazards[0..self.n_active].iter().find(|hz| !irrelevant_hazards.contains(&hz.entity)), } } @@ -108,15 +112,15 @@ impl QTHazardVec { pub fn has_only_entire_hazards(&self) -> bool { self.hazards.iter().all(|hz| matches!(hz.presence,QTHazPresence::Entire)) } +} - fn order_stronger(qth1: &QTHazard, qth2: &QTHazard) -> Ordering { - //sort by active, then by presence, so that the active hazards are always in front of inactive hazards, and Entire hazards are always in front of Partial hazards - match qth1.active.cmp(&qth2.active).reverse() { - Ordering::Equal => { - let (p1,p2): (u8, u8) = ((&qth1.presence).into(), (&qth2.presence).into()); - p1.cmp(&p2).reverse() - }, - other => other, +fn order_by_descending_strength(qth1: &QTHazard, qth2: &QTHazard) -> Ordering { +//sort in descending order of active (true > false) then by presence (Entire > Partial > None) + match qth1.active.cmp(&qth2.active).reverse() { + Ordering::Equal => { + let (p1, p2): (u8, u8) = ((&qth1.presence).into(), (&qth2.presence).into()); + p1.cmp(&p2).reverse() } + other => other, } } \ No newline at end of file diff --git a/jaguars/src/collision_detection/quadtree/qt_node.rs b/jaguars/src/collision_detection/quadtree/qt_node.rs index b826111..3363b6c 100644 --- a/jaguars/src/collision_detection/quadtree/qt_node.rs +++ b/jaguars/src/collision_detection/quadtree/qt_node.rs @@ -5,15 +5,19 @@ use crate::collision_detection::quadtree::qt_hazard::QTHazard; use crate::collision_detection::quadtree::qt_hazard::QTHazPresence; use crate::collision_detection::quadtree::qt_hazard_vec::QTHazardVec; use crate::collision_detection::quadtree::qt_partial_hazard::QTPartialHazard; -use crate::geometry::geo_traits::{CollidesWith, Shape}; +use crate::geometry::geo_traits::{CollidesWith}; use crate::geometry::primitives::aa_rectangle::AARectangle; use crate::geometry::primitives::point::Point; + +/// A node in the quadtree #[derive(Clone, Debug)] pub struct QTNode { + /// The level of the node in the tree, 0 being the bottom-most level level: u8, bbox: AARectangle, children: Option>, + /// The hazards present in the node hazards: QTHazardVec, } @@ -51,7 +55,7 @@ impl QTNode { //If the hazard is of the partial type, and we are not at the max tree depth: generate children if !self.has_children() && self.level > 0 && matches!(hazard.presence, QTHazPresence::Partial(_)) { self.generate_children(); - //register all existing hazard_filters to the newly created children + //register all existing hazards to the newly created children for hazard in self.hazards.all_hazards() { register_to_children(&mut self.children, hazard); } @@ -136,10 +140,10 @@ impl QTNode { /// Returns None if no collision between the entity and any hazard is detected, /// otherwise returns the first encountered hazard that collides with the entity - pub fn collides(&self, entity: &T, ignored_entities: &[HazardEntity]) -> Option<&HazardEntity> + pub fn collides(&self, entity: &T, irrelevant_hazards: &[HazardEntity]) -> Option<&HazardEntity> where T: CollidesWith, QTPartialHazard: CollidesWith { - match self.hazards.strongest(ignored_entities) { + match self.hazards.strongest(irrelevant_hazards) { None => None, Some(strongest_hazard) => match entity.collides_with(self.bbox()) { false => None, @@ -150,7 +154,7 @@ impl QTNode { Some(children) => { //Search if any of the children intersect with the entity children.iter() - .map(|child| child.collides(entity, ignored_entities)) + .map(|child| child.collides(entity, irrelevant_hazards)) .find(|x| x.is_some()) .flatten() } @@ -159,7 +163,7 @@ impl QTNode { match &hz.presence { QTHazPresence::Entire | QTHazPresence::None => {} //non-ignored Entire inclusion are caught by the previous match QTHazPresence::Partial(partial_hazard) => { - if !ignored_entities.contains(&hz.entity) { + if !irrelevant_hazards.contains(&hz.entity) { //do intersection test if this shape is not ignored if partial_hazard.collides_with(entity) { return Some(&hz.entity); @@ -176,10 +180,10 @@ impl QTNode { } } - pub fn definitely_collides(&self, entity: &T, ignored_entities: &[HazardEntity]) -> Tribool + pub fn definitely_collides(&self, entity: &T, irrelevant_hazards: &[HazardEntity]) -> Tribool where T: CollidesWith { - match self.hazards.strongest(ignored_entities) { + match self.hazards.strongest(irrelevant_hazards) { None => Tribool::False, Some(hazard) => match (entity.collides_with(self.bbox()), &hazard.presence) { (false, _) | (_, QTHazPresence::None) => Tribool::False, @@ -190,7 +194,7 @@ impl QTNode { let mut result = Tribool::False; //Assume no collision for i in 0..4 { let child = &children[i]; - match child.definitely_collides(entity, ignored_entities) { + match child.definitely_collides(entity, irrelevant_hazards) { Tribool::True => return Tribool::True, //If a child for sure collides, we can immediately return Yes Tribool::Indeterminate => result = Tribool::Indeterminate, //If a child might collide, switch from to Maybe Tribool::False => {} //If child does not collide, do nothing diff --git a/jaguars/src/collision_detection/quadtree/qt_partial_hazard.rs b/jaguars/src/collision_detection/quadtree/qt_partial_hazard.rs index 3aa7159..14f1d73 100644 --- a/jaguars/src/collision_detection/quadtree/qt_partial_hazard.rs +++ b/jaguars/src/collision_detection/quadtree/qt_partial_hazard.rs @@ -9,7 +9,7 @@ use crate::geometry::primitives::edge::Edge; use crate::geometry::primitives::simple_polygon::SimplePolygon; -/// QTPartialHazards define a set of edges from a hazard that cross the QTNode. +/// QTPartialHazards define a set of edges from a hazard that is partially active in the QTNode. #[derive(Clone, Debug)] pub struct QTPartialHazard { shape: Weak, @@ -68,7 +68,7 @@ impl QTPartialHazard { } impl CollidesWith for QTPartialHazard { fn collides_with(&self, edge: &Edge) -> bool { - let shape = self.shape.upgrade().expect("polygon reference is not alive"); + let shape = self.shape.upgrade().expect("polygon reference should be alive"); match self.edge_indices() { EdgeIndices::All => { match shape.bbox().collides_with(edge) { diff --git a/jaguars/src/entities/bin.rs b/jaguars/src/entities/bin.rs index 1b0c553..07b5a7b 100644 --- a/jaguars/src/entities/bin.rs +++ b/jaguars/src/entities/bin.rs @@ -13,8 +13,6 @@ use crate::geometry::transformation::Transformation; use crate::N_QUALITIES; use crate::util::config::CDEConfig; -//TODO: Add base quality to bins - #[derive(Clone, Debug)] pub struct Bin { id: usize, @@ -63,7 +61,6 @@ impl Bin { } pub fn from_strip(id: usize, width: f64, height: f64, cde_config: CDEConfig) -> Self { - //TODO: move this out of here let poly = SimplePolygon::from(AARectangle::new(0.0, 0.0, width, height)); let value = poly.area() as u64; diff --git a/jaguars/src/entities/item.rs b/jaguars/src/entities/item.rs index 87e0a5f..3fe8e29 100644 --- a/jaguars/src/entities/item.rs +++ b/jaguars/src/entities/item.rs @@ -22,7 +22,7 @@ impl Item { centering_transform: Transformation, base_quality: Option, surrogate_config: SPSurrogateConfig) -> Item { shape.generate_surrogate(surrogate_config); let shape = Arc::new(shape); - let hazard_filter = base_quality.map(|q| QZHazardFilter { base_quality: q }); + let hazard_filter = base_quality.map(|q| QZHazardFilter { cutoff_quality: q }); Item { id, shape, allowed_rotation, base_quality, value, centering_transform, hazard_filter } } diff --git a/jaguars/src/entities/problems/sp_problem.rs b/jaguars/src/entities/problems/sp_problem.rs index 5ba3e6c..4ed7e02 100644 --- a/jaguars/src/entities/problems/sp_problem.rs +++ b/jaguars/src/entities/problems/sp_problem.rs @@ -58,7 +58,7 @@ impl SPProblem { for p_uid in old_p_uids { let item = self.instance.item(p_uid.item_id); - let entities_to_ignore = item.hazard_filter().map_or(vec![], |f| hazard_filter::ignored_entities(f, self.layout.cde().all_hazards())); + let entities_to_ignore = item.hazard_filter().map_or(vec![], |f| hazard_filter::get_irrelevant_hazard_entities(f, self.layout.cde().all_hazards())); let shape = item.shape(); let transf = p_uid.d_transf.compose(); if !self.layout.cde().surrogate_collides(shape.surrogate(), &transf, entities_to_ignore.as_slice()) { diff --git a/jaguars/src/entities/solution.rs b/jaguars/src/entities/solution.rs index c7b10b1..275345d 100644 --- a/jaguars/src/entities/solution.rs +++ b/jaguars/src/entities/solution.rs @@ -6,6 +6,7 @@ use crate::entities::instance::{Instance, PackingType}; use crate::entities::layout::LayoutSnapshot; use crate::geometry::geo_traits::Shape; +//TODO: clean this up properly #[derive(Debug, Clone)] pub struct Solution { id: usize, diff --git a/jaguars/src/geometry/fail_fast/sp_surrogate.rs b/jaguars/src/geometry/fail_fast/sp_surrogate.rs index 30fb96d..b03cfcf 100644 --- a/jaguars/src/geometry/fail_fast/sp_surrogate.rs +++ b/jaguars/src/geometry/fail_fast/sp_surrogate.rs @@ -50,7 +50,7 @@ impl SPSurrogate { impl Transformable for SPSurrogate { fn transform(&mut self, t: &Transformation) -> &mut Self { - //destructuring pattern used to ensure that the code is updated when the struct changes + //destructuring pattern used to ensure that the code is updated accordingly when the struct changes let Self {convex_hull_indices: _, poles, poles_bounding_circle, piers, ff_pole_range: _} = self; //transform poles @@ -74,7 +74,7 @@ impl TransformableFrom for SPSurrogate { debug_assert!(self.poles.len() == reference.poles.len()); debug_assert!(self.piers.len() == reference.piers.len()); - //destructuring pattern used to ensure that the code is updated when the struct changes + //destructuring pattern used to ensure that the code is updated accordingly when the struct changes let Self {convex_hull_indices: _, poles, poles_bounding_circle, piers, ff_pole_range: _} = self; for (pole, ref_pole) in poles.iter_mut().zip(reference.poles.iter()) { diff --git a/jaguars/src/geometry/geo_traits.rs b/jaguars/src/geometry/geo_traits.rs index 81180cc..28c9295 100644 --- a/jaguars/src/geometry/geo_traits.rs +++ b/jaguars/src/geometry/geo_traits.rs @@ -23,7 +23,7 @@ pub trait DistanceFrom { fn sq_distance_from_border(&self, other: &T) -> (GeoPosition, f64); } -/// Trait for types that can be transformed +/// Trait for types that can be transformed by a Transformation pub trait Transformable: Clone { fn transform(&mut self, t: &Transformation) -> &mut Self; @@ -34,7 +34,7 @@ pub trait Transformable: Clone { } } -/// Trait for types that can be transformed based on a reference object +/// Trait for types that can be transformed based on a reference object with a Transformation applied pub trait TransformableFrom: Transformable { fn transform_from(&mut self, reference: &Self, t: &Transformation) -> &mut Self; } diff --git a/jaguars/src/geometry/primitives/aa_rectangle.rs b/jaguars/src/geometry/primitives/aa_rectangle.rs index 2244655..17084f8 100644 --- a/jaguars/src/geometry/primitives/aa_rectangle.rs +++ b/jaguars/src/geometry/primitives/aa_rectangle.rs @@ -69,50 +69,44 @@ impl AARectangle { ] } - pub fn relation_to(&self, rect: &AARectangle) -> GeoRelation { - if self.collides_with(rect) { - if self.x_min <= rect.x_min - && self.y_min <= rect.y_min - && self.x_max >= rect.x_max - && self.y_max >= rect.y_max - { - return GeoRelation::Surrounding; - } else if self.x_min >= rect.x_min - && self.y_min >= rect.y_min - && self.x_max <= rect.x_max - && self.y_max <= rect.y_max - { - return GeoRelation::Enclosed; - } else { - return GeoRelation::Intersecting; + pub fn relation_to(&self, other: &AARectangle) -> GeoRelation { + if self.collides_with(other) { + if self.x_min <= other.x_min && self.y_min <= other.y_min && + self.x_max >= other.x_max && self.y_max >= other.y_max { + GeoRelation::Surrounding + } + else if self.x_min >= other.x_min && self.y_min >= other.y_min && + self.x_max <= other.x_max && self.y_max <= other.y_max { + GeoRelation::Enclosed + } + else { + GeoRelation::Intersecting } + } else { + GeoRelation::Disjoint } - - GeoRelation::Disjoint } - pub fn almost_relation_to(&self, rect: &AARectangle) -> GeoRelation { - if self.almost_collides_with(rect) { - //rectangles have a relation - return if F64A::from(self.x_min) <= F64A::from(rect.x_min) - && F64A::from(self.y_min) <= F64A::from(rect.y_min) - && F64A::from(self.x_max) >= F64A::from(rect.x_max) - && F64A::from(self.y_max) >= F64A::from(rect.y_max) - { + pub fn almost_relation_to(&self, other: &AARectangle) -> GeoRelation { + if self.almost_collides_with(other) { + if F64A::from(self.x_min) <= F64A::from(other.x_min) && F64A::from(self.y_min) <= F64A::from(other.y_min) && + F64A::from(self.x_max) >= F64A::from(other.x_max) && F64A::from(self.y_max) >= F64A::from(other.y_max) { GeoRelation::Surrounding - } else if F64A::from(self.x_min) >= F64A::from(rect.x_min) - && F64A::from(self.y_min) >= F64A::from(rect.y_min) - && F64A::from(self.x_max) <= F64A::from(rect.x_max) - && F64A::from(self.y_max) <= F64A::from(rect.y_max) - { + } + else if F64A::from(self.x_min) >= F64A::from(other.x_min) && F64A::from(self.y_min) >= F64A::from(other.y_min) && + F64A::from(self.x_max) <= F64A::from(other.x_max) && F64A::from(self.y_max) <= F64A::from(other.y_max) { GeoRelation::Enclosed - } else { + } + else { GeoRelation::Intersecting } + } + else{ + GeoRelation::Disjoint } - GeoRelation::Disjoint } + /// Returns the rectangle that is the result of inflating the smallest dimension of the rectangle to match the largest dimension pub fn inflate_to_square(&self) -> AARectangle { let width = self.x_max - self.x_min; let height = self.y_max - self.y_min; @@ -142,10 +136,11 @@ impl AARectangle { self } + //array quadrant layout: [nw, ne, sw, se] + //e.g. cell with index 0 is neighbored by cells 1 and 2 + pub const QUADRANT_NEIGHBOR_LAYOUT: [[usize; 2]; 4] = [[1, 2], [0, 3], [0, 3], [1, 2]]; + pub fn quadrants(&self) -> [Self; 4] { - // nw|ne 0|1 - // ----- --- - // sw|se 2|3 let Point(x_mid, y_mid) = self.centroid(); let (x_min, y_min, x_max, y_max) = (self.x_min.into(), self.y_min.into(), self.x_max.into(), self.y_max.into()); diff --git a/jaguars/src/geometry/primitives/circle.rs b/jaguars/src/geometry/primitives/circle.rs index 6ac3dc8..198ae66 100644 --- a/jaguars/src/geometry/primitives/circle.rs +++ b/jaguars/src/geometry/primitives/circle.rs @@ -88,9 +88,7 @@ impl CollidesWith for Circle { #[inline(always)] fn collides_with(&self, rect: &AARectangle) -> bool { //Based on: https://yal.cc/rectangle-circle-intersection-test/ - - //TODO: benchmark this against approach which first checks only center - + let Point(c_x, c_y) = self.center; let nearest_x = f64::max(rect.x_min, f64::min(c_x, rect.x_max)); diff --git a/jaguars/src/util/assertions.rs b/jaguars/src/util/assertions.rs index 28a97e5..531cf7a 100644 --- a/jaguars/src/util/assertions.rs +++ b/jaguars/src/util/assertions.rs @@ -106,7 +106,7 @@ pub fn item_to_place_does_not_collide(item: &Item, transformation: &Transformati let t_shape = shape.transform_clone(transformation); let entities_to_ignore = haz_filter - .map_or(vec![], |f| hazard_filter::ignored_entities(f, layout.cde().all_hazards())); + .map_or(vec![], |f| hazard_filter::get_irrelevant_hazard_entities(f, layout.cde().all_hazards())); if layout.cde().surrogate_collides(shape.surrogate(), transformation, &entities_to_ignore) || layout.cde().shape_collides(&t_shape, &entities_to_ignore) { @@ -122,7 +122,7 @@ pub fn layout_is_collision_free(layout: &Layout) -> bool { None => CombinedHazardFilter::new().add(&hef), Some(hf) => CombinedHazardFilter::new().add(&hef).add(hf) }; - let entities_to_ignore = hazard_filter::ignored_entities(&combo_filter,layout.cde().all_hazards()); + let entities_to_ignore = hazard_filter::get_irrelevant_hazard_entities(&combo_filter, layout.cde().all_hazards()); if layout.cde().shape_collides(pi.shape(), &entities_to_ignore) { println!("Collision detected for item {:.?}", pi.uid()); @@ -261,19 +261,19 @@ fn qt_nodes_match(qn1: Option<&QTNode>, qn2: Option<&QTNode>) -> bool { let from_1 = **active_in_1_but_not_2.iter().next().unwrap(); let from_2 = **active_in_2_but_not_1.iter().next().unwrap(); println!("{}", from_1 == from_2); - error!("Active hazard_filters don't match {:?} vs {:?}", active_in_1_but_not_2, active_in_2_but_not_1); + error!("Active hazards don't match {:?} vs {:?}", active_in_1_but_not_2, active_in_2_but_not_1); return false; } } (Some(qn1), None) => { if qn1.hazards().active_hazards().iter().next().is_some() { - error!("qn1 contains active hazard_filters while other qn2 does not exist"); + error!("qn1 contains active hazards while other qn2 does not exist"); return false; } } (None, Some(qn2)) => { if qn2.hazards().active_hazards().iter().next().is_some() { - error!("qn2 contains active hazard_filters while other qn1 does not exist"); + error!("qn2 contains active hazards while other qn1 does not exist"); return false; } } diff --git a/jaguars/src/util/f64a.rs b/jaguars/src/util/f64a.rs index d32e3d2..a386331 100644 --- a/jaguars/src/util/f64a.rs +++ b/jaguars/src/util/f64a.rs @@ -2,8 +2,9 @@ use std::cmp::Ordering; use almost::AlmostEqual; -///Wrapper around the almost crate for easy comparison with tolerance of floats +///Wrapper around the almost crate for easy comparison of floats with a certain tolerance ///the almost crate considers two floats equal if they are within a certain tolerance of each other. +///see crate docs for more details pub struct F64A(pub f64); impl F64A { diff --git a/lbf/benches/fast_fail_bench.rs b/lbf/benches/fast_fail_bench.rs index 86f628e..ca8f4ca 100644 --- a/lbf/benches/fast_fail_bench.rs +++ b/lbf/benches/fast_fail_bench.rs @@ -37,7 +37,7 @@ criterion_group!(benches, fast_fail_query_bench); mod util; const FF_POLE_RANGE: RangeInclusive = 0..=4; -const FF_PIER_RANGE: RangeInclusive = 0..=4; +const FF_PIER_RANGE: RangeInclusive = 0..=0; /// Benchmark the query operation of the quadtree for different depths /// We validate 1000 sampled transformations for each of the 5 removed items diff --git a/lbf/src/io/svg_export.rs b/lbf/src/io/svg_export.rs index e815e2e..341e978 100644 --- a/lbf/src/io/svg_export.rs +++ b/lbf/src/io/svg_export.rs @@ -22,8 +22,8 @@ pub fn simple_polygon_data(s_poly: &SimplePolygon) -> Data { data.close() } -pub fn quad_tree_data(qt_root: &QTNode, ignored_entities: &[HazardEntity]) -> (Data, Data, Data) { - qt_node_data(qt_root, Data::new(), Data::new(), Data::new(), ignored_entities) +pub fn quad_tree_data(qt_root: &QTNode, irrelevant_hazards: &[HazardEntity]) -> (Data, Data, Data) { + qt_node_data(qt_root, Data::new(), Data::new(), Data::new(), irrelevant_hazards) } fn qt_node_data( @@ -31,15 +31,15 @@ fn qt_node_data( mut data_eh: Data, //entire inclusion data mut data_ph: Data, //partial inclusion data mut data_nh: Data, //no inclusion data - ignored_entities: &[HazardEntity], + irrelevant_hazards: &[HazardEntity], ) -> (Data, Data, Data) { //Only draw qt_nodes that do not have a child - match (qt_node.has_children(), qt_node.hazards().strongest(ignored_entities)) { + match (qt_node.has_children(), qt_node.hazards().strongest(irrelevant_hazards)) { (true, Some(_)) => { //not a leaf node, go to children for child in qt_node.children().as_ref().unwrap().iter() { - let data = qt_node_data(child, data_eh, data_ph, data_nh, ignored_entities); + let data = qt_node_data(child, data_eh, data_ph, data_nh, irrelevant_hazards); data_eh = data.0; data_ph = data.1; data_nh = data.2; @@ -57,7 +57,7 @@ fn qt_node_data( .close() }; - match qt_node.hazards().strongest(ignored_entities) { + match qt_node.hazards().strongest(irrelevant_hazards) { Some(ch) => { match ch.presence { QTHazPresence::Entire => data_eh = draw(data_eh), diff --git a/lbf/src/lbf_optimizer.rs b/lbf/src/lbf_optimizer.rs index 9614175..0fc901a 100644 --- a/lbf/src/lbf_optimizer.rs +++ b/lbf/src/lbf_optimizer.rs @@ -148,7 +148,7 @@ pub fn sample_layout(problem: &ProblemEnum, layout_index: LayoutIndex, item: &It let item_id = item.id(); let layout: &Layout = problem.get_layout(&layout_index); let entities_to_ignore = item.hazard_filter() - .map_or(vec![], |hf| hazard_filter::ignored_entities(hf, layout.cde().all_hazards())); + .map_or(vec![], |hf| hazard_filter::get_irrelevant_hazard_entities(hf, layout.cde().all_hazards())); let shape = item.shape(); let surrogate = item.shape().surrogate();