diff --git a/jagua-rs/src/collision_detection/hazard.rs b/jagua-rs/src/collision_detection/hazard.rs index 9700cc9..b791ba6 100644 --- a/jagua-rs/src/collision_detection/hazard.rs +++ b/jagua-rs/src/collision_detection/hazard.rs @@ -1,6 +1,8 @@ +use crate::entities::placed_item::PlacedItem; use crate::geometry::d_transformation::DTransformation; use crate::geometry::geo_enums::GeoPosition; use crate::geometry::primitives::simple_polygon::SimplePolygon; +use std::borrow::Borrow; use std::sync::Arc; /// Defines a certain spatial constraint that affects the feasibility of a placement. @@ -68,3 +70,15 @@ impl HazardEntity { } } } + +impl From for HazardEntity +where + T: Borrow, +{ + fn from(pi: T) -> Self { + HazardEntity::PlacedItem { + id: pi.borrow().item_id, + dt: pi.borrow().d_transf, + } + } +} diff --git a/jagua-rs/src/collision_detection/hazard_filter.rs b/jagua-rs/src/collision_detection/hazard_filter.rs index b6eb914..68fa83d 100644 --- a/jagua-rs/src/collision_detection/hazard_filter.rs +++ b/jagua-rs/src/collision_detection/hazard_filter.rs @@ -41,7 +41,7 @@ pub struct CombinedHazardFilter<'a> { impl HazardFilter for BinHazardFilter { fn is_irrelevant(&self, entity: &HazardEntity) -> bool { match entity { - HazardEntity::PlacedItem(_) => false, + HazardEntity::PlacedItem { .. } => false, HazardEntity::BinExterior => true, HazardEntity::BinHole { .. } => true, HazardEntity::InferiorQualityZone { .. } => true, diff --git a/jagua-rs/src/collision_detection/quadtree/qt_hazard_vec.rs b/jagua-rs/src/collision_detection/quadtree/qt_hazard_vec.rs index 788a5f5..e2083ed 100644 --- a/jagua-rs/src/collision_detection/quadtree/qt_hazard_vec.rs +++ b/jagua-rs/src/collision_detection/quadtree/qt_hazard_vec.rs @@ -27,7 +27,7 @@ impl QTHazardVec { self.hazards .iter() .filter(|other| other.entity == haz.entity - && matches!(haz.entity, HazardEntity::PlacedItem(_))) + && matches!(haz.entity, HazardEntity::PlacedItem { .. })) .count() == 0, "More than one hazard from same item entity in the vector! (This should never happen!)" @@ -48,7 +48,7 @@ impl QTHazardVec { self.hazards .iter() .filter(|ch| ch.entity == haz_entity - && matches!(ch.entity, HazardEntity::PlacedItem(_))) + && matches!(ch.entity, HazardEntity::PlacedItem { .. })) .count() <= 1, "More than one hazard from same item entity in the vector! (This should never happen!)" diff --git a/jagua-rs/src/entities/layout.rs b/jagua-rs/src/entities/layout.rs index 106b9a0..22dbfd3 100644 --- a/jagua-rs/src/entities/layout.rs +++ b/jagua-rs/src/entities/layout.rs @@ -1,5 +1,5 @@ use crate::collision_detection::cd_engine::{CDESnapshot, CDEngine}; -use crate::collision_detection::hazard::Hazard; +use crate::collision_detection::hazard::{Hazard, HazardEntity}; use crate::entities::bin::Bin; use crate::entities::item::Item; use crate::entities::placed_item::{PItemKey, PlacedItem}; @@ -48,8 +48,8 @@ impl Layout { self.bin = bin; // update the CDE self.cde = self.bin.base_cde.as_ref().clone(); - for (pik, pi) in self.placed_items.iter() { - let hazard = Hazard::new(pik.into(), pi.shape.clone()); + for (_, pi) in self.placed_items.iter() { + let hazard = Hazard::new(pi.into(), pi.shape.clone()); self.cde.register_hazard(hazard); } } @@ -79,10 +79,10 @@ impl Layout { } pub fn place_item(&mut self, item: &Item, d_transformation: DTransformation) -> PItemKey { - let placed_item = PlacedItem::new(item, d_transformation); - let pik = self.placed_items.insert(placed_item); + let pi = PlacedItem::new(item, d_transformation); + let hazard = Hazard::new(HazardEntity::from(&pi), pi.shape.clone()); - let hazard = Hazard::new(pik.into(), self.placed_items[pik].shape.clone()); + let pik = self.placed_items.insert(pi); self.cde.register_hazard(hazard); debug_assert!(assertions::layout_qt_matches_fresh_qt(self)); @@ -91,17 +91,18 @@ impl Layout { } pub fn remove_item(&mut self, key: PItemKey, commit_instant: bool) -> PlacedItem { - let p_item = self + let pi = self .placed_items .remove(key) .expect("key is not valid anymore"); // update the collision detection engine - self.cde.deregister_hazard(key.into(), commit_instant); + self.cde + .deregister_hazard(HazardEntity::from(&pi), commit_instant); debug_assert!(assertions::layout_qt_matches_fresh_qt(self)); - p_item + pi } /// True if no items are placed @@ -109,18 +110,21 @@ impl Layout { self.placed_items.is_empty() } - pub fn bin(&self) -> &Bin { - &self.bin - } - pub fn placed_items(&self) -> &SlotMap { &self.placed_items } + pub fn hazard_to_p_item_key(&self, hz: &HazardEntity) -> Option { + self.placed_items + .iter() + .find(|(_, pi)| HazardEntity::from(*pi) == *hz) + .map(|(k, _)| k) + } + /// Returns the usage of the bin with the items placed. /// It is the ratio of the area of the items placed to the area of the bin. pub fn usage(&self) -> fsize { - let bin_area = self.bin().area; + let bin_area = self.bin.area; let item_area = self .placed_items .iter() diff --git a/jagua-rs/src/entities/placed_item.rs b/jagua-rs/src/entities/placed_item.rs index 4498c9b..1253804 100644 --- a/jagua-rs/src/entities/placed_item.rs +++ b/jagua-rs/src/entities/placed_item.rs @@ -3,8 +3,14 @@ use crate::entities::item::Item; use crate::geometry::d_transformation::DTransformation; use crate::geometry::geo_traits::Transformable; use crate::geometry::primitives::simple_polygon::SimplePolygon; +use slotmap::new_key_type; use std::sync::Arc; +new_key_type! { + /// Unique key for each `PlacedItem` in a layout. + pub struct PItemKey; +} + /// Represents an `Item` that has been placed in a `Layout` #[derive(Clone, Debug)] pub struct PlacedItem { diff --git a/jagua-rs/src/entities/problems/bin_packing.rs b/jagua-rs/src/entities/problems/bin_packing.rs index 4e8191c..2b26a5c 100644 --- a/jagua-rs/src/entities/problems/bin_packing.rs +++ b/jagua-rs/src/entities/problems/bin_packing.rs @@ -64,7 +64,7 @@ impl BPProblem { } pub fn register_layout(&mut self, layout: Layout) -> LayoutIndex { - self.register_bin(layout.bin().id); + self.register_bin(layout.bin.id); layout .placed_items() .values() @@ -78,7 +78,7 @@ impl BPProblem { LayoutIndex::Real(i) => { let layout = self.layouts.remove(i); self.layout_has_changed(layout.id()); - self.deregister_bin(layout.bin().id); + self.deregister_bin(layout.bin.id); layout .placed_items() .values() diff --git a/jagua-rs/src/entities/problems/problem_generic.rs b/jagua-rs/src/entities/problems/problem_generic.rs index 6e67f45..68f7d92 100644 --- a/jagua-rs/src/entities/problems/problem_generic.rs +++ b/jagua-rs/src/entities/problems/problem_generic.rs @@ -53,7 +53,7 @@ pub trait ProblemGeneric: ProblemGenericPrivate { fn usage(&mut self) -> fsize { let (total_bin_area, total_used_area) = self.layouts_mut().iter_mut().fold((0.0, 0.0), |acc, l| { - let bin_area = l.bin().area; + let bin_area = l.bin.area; let used_area = bin_area * l.usage(); (acc.0 + bin_area, acc.1 + used_area) }); @@ -61,7 +61,7 @@ pub trait ProblemGeneric: ProblemGenericPrivate { } fn used_bin_cost(&self) -> u64 { - self.layouts().iter().map(|l| l.bin().value).sum() + self.layouts().iter().map(|l| l.bin.value).sum() } /// Returns the `LayoutIndex` of all layouts. @@ -74,7 +74,7 @@ pub trait ProblemGeneric: ProblemGenericPrivate { self.template_layouts() .iter() .enumerate() - .filter_map(|(i, l)| match self.bin_qtys()[l.bin().id] { + .filter_map(|(i, l)| match self.bin_qtys()[l.bin.id] { 0 => None, _ => Some(LayoutIndex::Template(i)), }) diff --git a/jagua-rs/src/entities/problems/strip_packing.rs b/jagua-rs/src/entities/problems/strip_packing.rs index 739403f..f941a91 100644 --- a/jagua-rs/src/entities/problems/strip_packing.rs +++ b/jagua-rs/src/entities/problems/strip_packing.rs @@ -54,7 +54,7 @@ impl SPProblem { /// Adds or removes width in the back of the strip. pub fn modify_strip_in_back(&mut self, new_width: fsize) { - let bbox = self.layout.bin().outer.bbox(); + let bbox = self.layout.bin.outer.bbox(); let new_strip_shape = AARectangle::new(bbox.x_min, bbox.y_min, bbox.x_min + new_width, bbox.y_max); self.modify_strip(new_strip_shape); @@ -62,7 +62,7 @@ impl SPProblem { /// Adds or removes width at the front of the strip. pub fn modify_strip_at_front(&mut self, new_width: fsize) { - let bbox = self.layout.bin().outer.bbox(); + let bbox = self.layout.bin.outer.bbox(); let new_strip_shape = AARectangle::new(bbox.x_max - new_width, bbox.y_min, bbox.x_max, bbox.y_max); self.modify_strip(new_strip_shape); @@ -80,9 +80,9 @@ impl SPProblem { let new_strip_shape = AARectangle::new( new_x_min, - self.layout.bin().outer.bbox().y_min, + self.layout.bin.outer.bbox().y_min, new_x_max, - self.layout.bin().outer.bbox().y_max, + self.layout.bin.outer.bbox().y_max, ); self.modify_strip(new_strip_shape); @@ -107,7 +107,7 @@ impl SPProblem { //Modifying the width causes the bin to change, so the layout must be replaced self.layout = Layout::new( self.next_layout_id(), - Bin::from_strip(rect, self.layout.bin().base_cde.config()), + Bin::from_strip(rect, self.layout.bin.base_cde.config()), ); //place the items back in the new layout @@ -168,11 +168,11 @@ impl SPProblem { } pub fn strip_width(&self) -> fsize { - self.layout.bin().outer.bbox().width() + self.layout.bin.outer.bbox().width() } pub fn strip_height(&self) -> fsize { - self.layout.bin().outer.bbox().height() + self.layout.bin.outer.bbox().height() } } diff --git a/jagua-rs/src/io/parser.rs b/jagua-rs/src/io/parser.rs index f1397a2..71b15c1 100644 --- a/jagua-rs/src/io/parser.rs +++ b/jagua-rs/src/io/parser.rs @@ -298,7 +298,7 @@ pub fn build_strip_packing_solution( let transform = absolute_to_internal_transform( &abs_transform, &item.pretransform, - &problem.layout.bin().pretransform, + &problem.layout.bin.pretransform, ); let d_transf = transform.decompose(); @@ -332,7 +332,7 @@ pub fn build_bin_packing_solution(instance: &BPInstance, json_layouts: &[JsonLay let template_index = problem .template_layouts() .iter() - .position(|tl| tl.bin().id == bin.id) + .position(|tl| tl.bin.id == bin.id) .expect("no template layout found for bin"); let json_first_item = json_layout diff --git a/jagua-rs/src/util/assertions.rs b/jagua-rs/src/util/assertions.rs index 1cdc28d..2e71851 100644 --- a/jagua-rs/src/util/assertions.rs +++ b/jagua-rs/src/util/assertions.rs @@ -51,7 +51,7 @@ pub fn problem_matches_solution(problem: &P, solution: &Solut } pub fn layouts_match(layout: &Layout, layout_snapshot: &LayoutSnapshot) -> bool { - if layout.bin().id != layout_snapshot.bin.id { + if layout.bin.id != layout_snapshot.bin.id { return false; } for placed_item in layout_snapshot.placed_items.values() { @@ -120,8 +120,8 @@ pub fn item_to_place_does_not_collide( } pub fn layout_is_collision_free(layout: &Layout) -> bool { - for (key, pi) in layout.placed_items().iter() { - let ehf = EntityHazardFilter(vec![key.into()]); + for (_, pi) in layout.placed_items().iter() { + let ehf = EntityHazardFilter(vec![pi.into()]); let combo_filter = match &pi.hazard_filter { None => CombinedHazardFilter { @@ -254,10 +254,10 @@ pub fn layout_qt_matches_fresh_qt(layout: &Layout) -> bool { //check if every placed item is correctly represented in the quadtree //rebuild the quadtree - let bin = layout.bin(); + let bin = &layout.bin; let mut fresh_cde = bin.base_cde.as_ref().clone(); - for (pik, pi) in layout.placed_items().iter() { - let hazard = Hazard::new(pik.into(), pi.shape.clone()); + for (_, pi) in layout.placed_items().iter() { + let hazard = Hazard::new(pi.into(), pi.shape.clone()); fresh_cde.register_hazard(hazard); } diff --git a/jagua-rs/src/util/mod.rs b/jagua-rs/src/util/mod.rs index ef879ee..e53e660 100644 --- a/jagua-rs/src/util/mod.rs +++ b/jagua-rs/src/util/mod.rs @@ -15,7 +15,7 @@ pub mod polygon_simplification; pub fn print_layout(layout: &Layout) { println!( "let mut layout = Layout::new(0, instance.bin({}).clone());", - layout.bin().id + layout.bin.id ); println!(); diff --git a/lbf/benches/edge_sensitivity_bench.rs b/lbf/benches/edge_sensitivity_bench.rs index 9d7b4a1..f487c09 100644 --- a/lbf/benches/edge_sensitivity_bench.rs +++ b/lbf/benches/edge_sensitivity_bench.rs @@ -93,7 +93,7 @@ fn edge_sensitivity_bench(config: LBFConfig, mut g: BenchmarkGroup) { let layout = problem.get_layout(LayoutIndex::Real(0)); /*let samples = { - let sampler = UniformAARectSampler::new(layout.bin().bbox(), instance.item(0)); + let sampler = UniformAARectSampler::new(layout.bin.bbox(), instance.item(0)); (0..N_SAMPLES).map( |_| sampler.sample(&mut rng).compose() ).collect_vec() diff --git a/lbf/benches/hpg_bench.rs b/lbf/benches/hpg_bench.rs index 3e633b4..1de64fd 100644 --- a/lbf/benches/hpg_bench.rs +++ b/lbf/benches/hpg_bench.rs @@ -94,7 +94,7 @@ fn hpg_query_bench(c: &mut Criterion) { println!( "[{}] sampler coverage: {:.3}% with {} samplers", n_hpg_cells, - sampler.coverage_area / layout.bin().bbox().area() * 100.0, + sampler.coverage_area / layout.bin.bbox().area() * 100.0, sampler.cell_samplers.len() ); @@ -182,7 +182,7 @@ fn hpg_update_bench(c: &mut Criterion) { println!( "[{}] sampler coverage: {:.3}% with {} samplers", n_hpg_cells, - sampler.coverage_area / layout.bin().bbox().area() * 100.0, + sampler.coverage_area / layout.bin.bbox().area() * 100.0, sampler.cell_samplers.len() ); diff --git a/lbf/benches/quadtree_bench.rs b/lbf/benches/quadtree_bench.rs index 599ba3d..1f03f63 100644 --- a/lbf/benches/quadtree_bench.rs +++ b/lbf/benches/quadtree_bench.rs @@ -20,9 +20,9 @@ use crate::util::{create_base_config, N_ITEMS_REMOVED, SWIM_PATH}; criterion_main!(benches); criterion_group!( benches, - //quadtree_query_update_1000_1, - //quadtree_query_bench, - //quadtree_update_bench, + quadtree_query_update_1000_1, + quadtree_query_bench, + quadtree_update_bench, quadtree_collect_query_bench ); @@ -110,7 +110,7 @@ fn quadtree_query_bench(c: &mut Criterion) { util::create_blf_problem(instance.clone(), config, N_ITEMS_REMOVED); let layout = problem.get_layout(LayoutIndex::Real(0)); - let sampler = UniformAARectSampler::new(layout.bin().bbox(), instance.item(0)); + let sampler = UniformAARectSampler::new(layout.bin.bbox(), instance.item(0)); let mut rng = SmallRng::seed_from_u64(0); let samples = (0..N_TOTAL_SAMPLES) @@ -170,7 +170,7 @@ fn quadtree_query_update_1000_1(c: &mut Criterion) { let (mut problem, _) = util::create_blf_problem(instance.clone(), config, N_ITEMS_REMOVED); let layout = problem.get_layout(LayoutIndex::Real(0)); - let sampler = UniformAARectSampler::new(layout.bin().bbox(), instance.item(0)); + let sampler = UniformAARectSampler::new(layout.bin.bbox(), instance.item(0)); let mut rng = SmallRng::seed_from_u64(0); let samples = (0..N_TOTAL_SAMPLES) @@ -241,7 +241,7 @@ fn quadtree_collect_query_bench(c: &mut Criterion) { util::create_blf_problem(instance.clone(), config, N_ITEMS_REMOVED); let layout = problem.get_layout(LayoutIndex::Real(0)); - let sampler = UniformAARectSampler::new(layout.bin().bbox(), instance.item(0)); + let sampler = UniformAARectSampler::new(layout.bin.bbox(), instance.item(0)); let mut rng = SmallRng::seed_from_u64(0); let samples = (0..N_TOTAL_SAMPLES) diff --git a/lbf/src/io/layout_to_svg.rs b/lbf/src/io/layout_to_svg.rs index 7219c15..3cc2bb6 100644 --- a/lbf/src/io/layout_to_svg.rs +++ b/lbf/src/io/layout_to_svg.rs @@ -21,7 +21,7 @@ pub fn s_layout_to_svg( } pub fn layout_to_svg(layout: &Layout, instance: &Instance, options: SvgDrawOptions) -> Document { - let internal_bin = layout.bin(); + let internal_bin = &layout.bin; let inv_bin_transf = internal_bin.pretransform.clone().inverse(); let bin = parser::pretransform_bin(internal_bin, &inv_bin_transf); diff --git a/lbf/src/lbf_optimizer.rs b/lbf/src/lbf_optimizer.rs index 57f6332..1afec3e 100644 --- a/lbf/src/lbf_optimizer.rs +++ b/lbf/src/lbf_optimizer.rs @@ -240,7 +240,7 @@ pub fn sample_layout( And the standard deviation tightens, to focus the search around the best sample. */ - let mut ls_sampler = LSSampler::from_defaults(item, &best_opt.d_transf, &layout.bin().bbox()); + let mut ls_sampler = LSSampler::from_defaults(item, &best_opt.d_transf, &layout.bin.bbox()); for i in 0..ls_sample_budget { let d_transf = ls_sampler.sample(rng); diff --git a/lbf/src/samplers/hpg_sampler.rs b/lbf/src/samplers/hpg_sampler.rs index f154bcd..f424d24 100644 --- a/lbf/src/samplers/hpg_sampler.rs +++ b/lbf/src/samplers/hpg_sampler.rs @@ -29,7 +29,7 @@ pub struct HPGSampler<'a> { impl<'a> HPGSampler<'a> { pub fn new(item: &'a Item, layout: &Layout) -> Option> { let poi = &item.shape.poi; - let bin_bbox = layout.bin().bbox(); + let bin_bbox = layout.bin.bbox(); //create a pre-transformation which centers the shape around its Pole of Inaccessibility. let pretransform = Transformation::from_translation((-poi.center.0, -poi.center.1));