jagua_rs/probs/spp/io/
import.rs

1use crate::entities::{Instance, Item};
2use crate::geometry::DTransformation;
3use crate::geometry::shape_modification::ShapeModifyConfig;
4use crate::io::import::{Importer, ext_to_int_transformation};
5use crate::probs::spp::entities::{SPInstance, SPPlacement, SPProblem, SPSolution, Strip};
6use crate::probs::spp::io::ext_repr::{ExtSPInstance, ExtSPSolution};
7use anyhow::{Result, ensure};
8use itertools::Itertools;
9use rayon::prelude::*;
10
11/// Imports an instance into the library
12#[allow(clippy::cast_precision_loss)]
13pub fn import_instance(importer: &Importer, ext_instance: &ExtSPInstance) -> Result<SPInstance> {
14    let items: Vec<(Item, usize)> = {
15        let mut items = ext_instance
16            .items
17            .par_iter()
18            .map(|ext_item| {
19                let item = importer.import_item(&ext_item.base)?;
20                let demand = usize::try_from(ext_item.demand).unwrap();
21                Ok((item, demand))
22            })
23            .collect::<Result<Vec<(Item, usize)>>>()?;
24
25        items.sort_by_key(|(item, _)| item.id);
26        items.retain(|(_, demand)| *demand > 0);
27
28        ensure!(
29            items.iter().enumerate().all(|(i, (item, _))| item.id == i),
30            "All items should have consecutive IDs starting from 0. IDs: {:?}",
31            items.iter().map(|(item, _)| item.id).sorted().collect_vec()
32        );
33        ensure!(
34            !items.is_empty(),
35            "ExtSPInstance must have at least one item with positive demand"
36        );
37
38        items
39    };
40
41    let total_item_area = items
42        .iter()
43        .map(|(item, demand)| item.area() * *demand as f32)
44        .sum::<f32>();
45
46    let fixed_height = ext_instance.strip_height;
47
48    // Initialize the base width for 100% density
49    let width = total_item_area / fixed_height;
50
51    let base_strip = Strip::new(
52        fixed_height,
53        importer.cde_config,
54        ShapeModifyConfig {
55            offset: importer.shape_modify_config.offset,
56            simplify_tolerance: None,
57            narrow_concavity_cutoff: None,
58        },
59        width,
60    )?;
61
62    Ok(SPInstance::new(items, base_strip))
63}
64
65/// Imports a solution into the library.
66#[must_use]
67pub fn import_solution(instance: &SPInstance, ext_solution: &ExtSPSolution) -> SPSolution {
68    let mut prob = SPProblem::new(instance.clone());
69    prob.change_strip_width(ext_solution.strip_width);
70
71    for ext_placement in ext_solution.layout.placed_items.iter().cloned() {
72        let item_id = usize::try_from(ext_placement.item_id).unwrap();
73        let d_transf = {
74            let ext_transf = DTransformation::from(ext_placement.transformation);
75            let item = &instance.item(item_id);
76            ext_to_int_transformation(&ext_transf, &item.shape_orig.pre_transform)
77        };
78        prob.place_item(SPPlacement { item_id, d_transf });
79    }
80
81    prob.save()
82}