Skip to main content

ak_vis/viewer/session/
selection.rs

1use ak_core::Trajectory;
2
3#[derive(Clone, Debug, PartialEq, Eq)]
4pub struct SelectionFrames {
5    pub(super) frames: Vec<Vec<bool>>,
6    pub(super) ordered: Vec<Vec<usize>>,
7}
8
9#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
10pub struct SelectedImageAtom {
11    pub atom_index: usize,
12    pub image_offset: [i32; 3],
13}
14
15#[derive(Clone, Debug, PartialEq, Eq)]
16pub struct ImageSelectionFrames {
17    pub(super) frames: Vec<Vec<SelectedImageAtom>>,
18}
19
20impl SelectionFrames {
21    pub fn new(traj: &Trajectory) -> Self {
22        Self {
23            frames: (0..traj.len())
24                .map(|index| vec![false; traj.view(index).positions.len()])
25                .collect(),
26            ordered: vec![Vec::new(); traj.len()],
27        }
28    }
29
30    pub fn get(&self, frame_index: usize) -> Option<&[bool]> {
31        self.frames.get(frame_index).map(Vec::as_slice)
32    }
33
34    pub fn replace(&mut self, frame_index: usize, selection: Vec<bool>) {
35        if frame_index < self.frames.len() && self.frames[frame_index].len() == selection.len() {
36            self.frames[frame_index] = selection;
37            self.ordered[frame_index] = self.frames[frame_index]
38                .iter()
39                .enumerate()
40                .filter_map(|(index, selected)| selected.then_some(index))
41                .collect();
42        }
43    }
44
45    pub fn add(&mut self, frame_index: usize, selection: &[bool]) {
46        if let Some(current) = self.frames.get_mut(frame_index) {
47            if current.len() != selection.len() {
48                return;
49            }
50            for (slot, selected) in current.iter_mut().zip(selection.iter().copied()) {
51                *slot |= selected;
52            }
53            let ordered = &mut self.ordered[frame_index];
54            for (index, selected) in selection.iter().copied().enumerate() {
55                if selected && current[index] && !ordered.contains(&index) {
56                    ordered.push(index);
57                }
58            }
59        }
60    }
61
62    pub fn remove(&mut self, frame_index: usize, selection: &[bool]) {
63        if let Some(current) = self.frames.get_mut(frame_index) {
64            if current.len() != selection.len() {
65                return;
66            }
67            for (slot, selected) in current.iter_mut().zip(selection.iter().copied()) {
68                if selected {
69                    *slot = false;
70                }
71            }
72            self.ordered[frame_index].retain(|index| current.get(*index).copied().unwrap_or(false));
73        }
74    }
75
76    pub fn clear(&mut self, frame_index: usize) {
77        if let Some(current) = self.frames.get_mut(frame_index) {
78            current.fill(false);
79            self.ordered[frame_index].clear();
80        }
81    }
82
83    pub fn append_empty_for_atom_count(&mut self, atom_count: usize) {
84        self.frames.push(vec![false; atom_count]);
85        self.ordered.push(Vec::new());
86    }
87
88    pub fn selected_main_images(&self, frame_index: usize) -> Vec<SelectedImageAtom> {
89        self.selected_indices(frame_index)
90            .into_iter()
91            .map(|atom_index| SelectedImageAtom {
92                atom_index,
93                image_offset: [0, 0, 0],
94            })
95            .collect()
96    }
97
98    pub fn selected_indices(&self, frame_index: usize) -> Vec<usize> {
99        self.ordered.get(frame_index).cloned().unwrap_or_default()
100    }
101
102    pub(crate) fn set_order(&mut self, frame_index: usize, ordered: Vec<usize>) {
103        if frame_index < self.ordered.len() {
104            self.ordered[frame_index] = ordered;
105        }
106    }
107
108    pub(crate) fn mask_from_images(atom_count: usize, atoms: &[SelectedImageAtom]) -> Vec<bool> {
109        let mut mask = vec![false; atom_count];
110        for atom in atoms {
111            if atom.atom_index < atom_count {
112                mask[atom.atom_index] = true;
113            }
114        }
115        mask
116    }
117
118    pub(crate) fn ordered_atoms_from_images(atoms: &[SelectedImageAtom]) -> Vec<usize> {
119        let mut ordered = Vec::new();
120        for atom in atoms {
121            if !ordered.contains(&atom.atom_index) {
122                ordered.push(atom.atom_index);
123            }
124        }
125        ordered
126    }
127}
128
129impl ImageSelectionFrames {
130    pub fn new(frame_count: usize) -> Self {
131        Self {
132            frames: vec![Vec::new(); frame_count],
133        }
134    }
135
136    pub fn get(&self, frame_index: usize) -> Option<&[SelectedImageAtom]> {
137        self.frames.get(frame_index).map(Vec::as_slice)
138    }
139
140    pub fn selected(&self, frame_index: usize) -> Vec<SelectedImageAtom> {
141        self.frames.get(frame_index).cloned().unwrap_or_default()
142    }
143
144    pub fn replace(&mut self, frame_index: usize, selection: Vec<SelectedImageAtom>) {
145        if frame_index < self.frames.len() {
146            self.frames[frame_index] = dedup_image_selection(selection);
147        }
148    }
149
150    pub fn add(&mut self, frame_index: usize, selection: &[SelectedImageAtom]) {
151        let Some(current) = self.frames.get_mut(frame_index) else {
152            return;
153        };
154        for atom in selection.iter().copied() {
155            if !current.contains(&atom) {
156                current.push(atom);
157            }
158        }
159    }
160
161    pub fn remove(&mut self, frame_index: usize, selection: &[SelectedImageAtom]) {
162        let Some(current) = self.frames.get_mut(frame_index) else {
163            return;
164        };
165        current.retain(|atom| !selection.contains(atom));
166    }
167
168    pub fn clear(&mut self, frame_index: usize) {
169        if frame_index < self.frames.len() {
170            self.frames[frame_index].clear();
171        }
172    }
173
174    pub fn append_empty_frame(&mut self) {
175        self.frames.push(Vec::new());
176    }
177
178    pub(super) fn replace_single(&mut self, frame_index: usize, atom: SelectedImageAtom) -> bool {
179        let Some(current) = self.frames.get_mut(frame_index) else {
180            return false;
181        };
182        if current.as_slice() == [atom] {
183            return false;
184        }
185        current.clear();
186        current.push(atom);
187        true
188    }
189
190    pub(super) fn toggle(&mut self, frame_index: usize, atom: SelectedImageAtom) -> bool {
191        let Some(current) = self.frames.get_mut(frame_index) else {
192            return false;
193        };
194        if let Some(index) = current.iter().position(|selected| *selected == atom) {
195            current.remove(index);
196        } else {
197            current.push(atom);
198        }
199        true
200    }
201}
202
203fn dedup_image_selection(selection: Vec<SelectedImageAtom>) -> Vec<SelectedImageAtom> {
204    let mut deduped = Vec::new();
205    for atom in selection {
206        if !deduped.contains(&atom) {
207            deduped.push(atom);
208        }
209    }
210    deduped
211}