ak_vis/viewer/session/
selection.rs

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