Skip to main content

jagua_rs/probs/spp/io/
import.rs

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