Skip to main content

jagua_rs/probs/spp/entities/
instance.rs

1use crate::entities::Item;
2use crate::probs::spp::entities::Strip;
3use crate::probs::spp::util::assertions;
4use itertools::Itertools;
5use std::sync::Arc;
6
7#[derive(Debug, Clone)]
8/// Instance of the Strip Packing Problem.
9pub struct SPInstance {
10    /// The items to be packed and their demands
11    pub items: Vec<(Arc<Item>, usize)>,
12    /// The strip in which to pack the items
13    pub base_strip: Strip,
14}
15
16impl SPInstance {
17    #[must_use]
18    pub fn new(items: Vec<(Arc<Item>, usize)>, base_strip: Strip) -> Self {
19        assert!(
20            assertions::instance_item_indices_correct(&items),
21            "Item indices should match their positions"
22        );
23
24        assert!(items.iter().map(|(item, _)| item.external_id).all_unique());
25        Self { items, base_strip }
26    }
27
28    #[allow(clippy::cast_precision_loss)]
29    #[must_use]
30    pub fn item_area(&self) -> f32 {
31        self.items
32            .iter()
33            .map(|(item, qty)| item.shape_orig.area() * *qty as f32)
34            .sum()
35    }
36
37    #[must_use]
38    pub fn item_qty(&self, idx: usize) -> usize {
39        self.items[idx].1
40    }
41
42    #[must_use]
43    pub fn total_item_qty(&self) -> usize {
44        self.items.iter().map(|(_, qty)| *qty).sum()
45    }
46
47    /// Retrieve an item by its internal index.
48    #[must_use]
49    pub fn item(&self, idx: usize) -> &Arc<Item> {
50        &self.items[idx].0
51    }
52
53    /// Resolve an external item ID, returning None for unknown or zero-demand items.
54    #[must_use]
55    pub fn item_idx(&self, external_id: u64) -> Option<usize> {
56        self.items
57            .iter()
58            .find(|(item, _)| item.external_id == external_id)
59            .map(|(item, _)| item.idx)
60    }
61}