jagua_rs/probs/spp/io/
import.rs1use 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#[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 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
68pub 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}