rvlib/tools_data/
mod.rs

1use crate::{
2    drawme::{Annotation, BboxAnnotation, Stroke},
3    BrushAnnotation,
4};
5
6pub use self::core::{
7    vis_from_lfoption, AccessInstanceData, Annotate, ExportAsCoco, ImportExportTrigger, ImportMode,
8    InstanceAnnotate, InstanceExportData, LabelInfo, Options, VisibleInactiveToolsState,
9    OUTLINE_THICKNESS_CONVERSION,
10};
11pub use self::{
12    attributes_data::AttributesToolData, bbox_data::BboxToolData, brush_data::BrushToolData,
13    coco_io::write_coco, plot_stats::PlotAnnotationStats, rot90_data::Rot90ToolData,
14};
15use rvimage_domain::{rverr, RvResult, TPtF};
16use serde::{Deserialize, Serialize};
17pub mod annotations;
18pub mod attributes_data;
19pub mod bbox_data;
20pub mod brush_data;
21pub mod coco_io;
22mod core;
23mod label_map;
24mod plot_stats;
25pub mod rot90_data;
26pub use core::{merge, AnnotationsMap, InstanceLabelDisplay, Options as CoreOptions};
27use std::collections::HashMap;
28
29macro_rules! variant_access {
30    ($variant:ident, $func_name:ident, $self:ty, $return_type:ty) => {
31        pub fn $func_name(self: $self) -> rvimage_domain::RvResult<$return_type> {
32            match self {
33                ToolSpecifics::$variant(x) => Ok(x),
34                _ => Err(rvimage_domain::rverr!(
35                    "this is not a {}",
36                    stringify!($variant)
37                )),
38            }
39        }
40    };
41}
42macro_rules! variant_access_free {
43    ($variant:ident, $func_name:ident, $lt:lifetime, $ToolsSpecific:ty, $return_type:ty) => {
44        pub fn $func_name<$lt>(x: $ToolsSpecific) -> rvimage_domain::RvResult<$return_type> {
45            match x {
46                ToolSpecifics::$variant(x) => Ok(x),
47                _ => Err(rvimage_domain::rverr!(
48                    "this is not a {}",
49                    stringify!($variant)
50                )),
51            }
52        }
53    };
54}
55
56variant_access_free!(Bbox, bbox, 'a, &'a ToolSpecifics, &'a BboxToolData);
57variant_access_free!(Bbox, bbox_mut, 'a, &'a mut ToolSpecifics, &'a mut BboxToolData);
58variant_access_free!(Brush, brush, 'a, &'a ToolSpecifics, &'a BrushToolData);
59variant_access_free!(Brush, brush_mut, 'a, &'a mut ToolSpecifics, &'a mut BrushToolData);
60variant_access_free!(Attributes, attributes, 'a, &'a ToolSpecifics, &'a AttributesToolData);
61variant_access_free!(Attributes, attributes_mut, 'a, &'a mut ToolSpecifics, &'a mut AttributesToolData);
62
63#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
64#[allow(clippy::large_enum_variant)]
65pub enum ToolSpecifics {
66    Bbox(BboxToolData),
67    Brush(BrushToolData),
68    Rot90(Rot90ToolData),
69    Zoom(()),
70    AlwaysActiveZoom(()),
71    Attributes(AttributesToolData),
72}
73impl ToolSpecifics {
74    variant_access!(Bbox, bbox, &Self, &BboxToolData);
75    variant_access!(Brush, brush, &Self, &BrushToolData);
76    variant_access!(Rot90, rot90, &Self, &Rot90ToolData);
77    variant_access!(Attributes, attributes, &Self, &AttributesToolData);
78    variant_access!(Bbox, bbox_mut, &mut Self, &mut BboxToolData);
79    variant_access!(Brush, brush_mut, &mut Self, &mut BrushToolData);
80    variant_access!(Rot90, rot90_mut, &mut Self, &mut Rot90ToolData);
81    variant_access!(
82        Attributes,
83        attributes_mut,
84        &mut Self,
85        &mut AttributesToolData
86    );
87
88    pub fn apply_mut<T>(
89        &mut self,
90        f_bbox: impl FnOnce(&mut BboxToolData) -> RvResult<T>,
91        f_brush: impl FnOnce(&mut BrushToolData) -> RvResult<T>,
92        f_attr: impl FnOnce(&mut AttributesToolData) -> RvResult<T>,
93    ) -> RvResult<T> {
94        match self {
95            Self::Bbox(bbox_data) => f_bbox(bbox_data),
96            Self::Brush(brush_data) => f_brush(brush_data),
97            Self::Attributes(attr_data) => f_attr(attr_data),
98            _ => Err(rverr!("only brush tool and bbox tool can be used in apply")),
99        }
100    }
101    pub fn apply<T>(
102        &self,
103        f_bbox: impl FnOnce(&BboxToolData) -> RvResult<T>,
104        f_brush: impl FnOnce(&BrushToolData) -> RvResult<T>,
105    ) -> RvResult<T> {
106        match self {
107            Self::Bbox(bbox_data) => f_bbox(bbox_data),
108            Self::Brush(brush_data) => f_brush(brush_data),
109            _ => Err(rverr!("only brush tool and bbox tool can be used in apply")),
110        }
111    }
112
113    pub fn to_annotations_view(
114        &self,
115        file_path_relative: &str,
116        only_cat_idx: Option<usize>,
117    ) -> Option<Vec<Annotation>> {
118        match self {
119            ToolSpecifics::Bbox(bb_data) => {
120                if let Some(annos) = bb_data.get_annos(file_path_relative) {
121                    let geos = annos.elts();
122                    let cats = annos.cat_idxs();
123                    let selected_bbs = annos.selected_mask();
124                    let labels = bb_data.label_info.labels();
125                    let colors = bb_data.label_info.colors();
126                    let bbs_colored = geos
127                        .iter()
128                        .zip(cats.iter())
129                        .zip(selected_bbs.iter())
130                        .filter(|((_, cat_idx), _)| {
131                            if let Some(only_cat_idx) = only_cat_idx {
132                                **cat_idx == only_cat_idx
133                            } else {
134                                true
135                            }
136                        })
137                        .map(|((geo, cat_idx), is_selected)| {
138                            Annotation::Bbox(BboxAnnotation {
139                                geofig: geo.clone(),
140                                fill_color: Some(colors[*cat_idx]),
141                                fill_alpha: bb_data.options.fill_alpha,
142                                label: Some(labels[*cat_idx].clone()),
143                                outline: Stroke {
144                                    thickness: TPtF::from(bb_data.options.outline_thickness)
145                                        / OUTLINE_THICKNESS_CONVERSION,
146                                    color: colors[*cat_idx],
147                                },
148                                outline_alpha: bb_data.options.outline_alpha,
149                                is_selected: Some(*is_selected),
150                                highlight_circles: bb_data.highlight_circles.clone(),
151                                instance_label_display: bb_data.options.core.instance_label_display,
152                            })
153                        })
154                        .collect::<Vec<Annotation>>();
155                    Some(bbs_colored)
156                } else {
157                    Some(vec![])
158                }
159            }
160            ToolSpecifics::Brush(br_data) => {
161                if let Some(annos) = br_data.get_annos(file_path_relative) {
162                    let colors = br_data.label_info.colors();
163                    let cats = annos.cat_idxs();
164                    let selected_mask = annos.selected_mask();
165                    let labels = br_data.label_info.labels();
166                    let annos = annos
167                        .elts()
168                        .iter()
169                        .zip(cats.iter())
170                        .zip(selected_mask.iter())
171                        .filter(|((_, cat_idx), _)| {
172                            if let Some(only_cat_idx) = only_cat_idx {
173                                **cat_idx == only_cat_idx
174                            } else {
175                                true
176                            }
177                        })
178                        .map(|((brush_line, cat_idx), is_selected)| {
179                            Annotation::Brush(BrushAnnotation {
180                                canvas: brush_line.clone(),
181                                color: colors[*cat_idx],
182                                label: Some(labels[*cat_idx].clone()),
183                                is_selected: Some(*is_selected),
184                                fill_alpha: br_data.options.fill_alpha,
185                                instance_display_label: br_data.options.core.instance_label_display,
186                            })
187                        })
188                        .collect::<Vec<Annotation>>();
189                    Some(annos)
190                } else {
191                    Some(vec![])
192                }
193            }
194            _ => None,
195        }
196    }
197}
198impl Default for ToolSpecifics {
199    fn default() -> Self {
200        ToolSpecifics::Bbox(BboxToolData::default())
201    }
202}
203
204#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq)]
205pub struct ToolsData {
206    pub specifics: ToolSpecifics,
207    pub menu_active: bool,
208    #[serde(default)]
209    pub visible_inactive_tools: VisibleInactiveToolsState,
210}
211impl ToolsData {
212    pub fn new(
213        specifics: ToolSpecifics,
214        visible_inactive_tools: VisibleInactiveToolsState,
215    ) -> Self {
216        ToolsData {
217            specifics,
218            menu_active: false,
219            visible_inactive_tools,
220        }
221    }
222}
223
224#[macro_export]
225macro_rules! toolsdata_by_name {
226    ($name:expr, $acc:ident, $tdm:expr) => {
227        $tdm.get_mut($name)
228            .ok_or(rvimage_domain::rverr!("{} is not a tool", $name))?
229            .specifics
230            .$acc()?
231    };
232}
233
234// tool name -> tool's menu data type
235pub type ToolsDataMap = HashMap<String, ToolsData>;
236
237#[macro_export]
238macro_rules! get_specifics_mut_from_tdm {
239    ($actor_name:expr, $tdm:expr, $access_func:ident) => {
240        $tdm.get_mut($actor_name)
241            .and_then(|x| x.specifics.$access_func().ok())
242    };
243}
244#[macro_export]
245macro_rules! get_specifics_from_tdm {
246    ($actor_name:expr, $tdm:expr, $access_func:ident) => {
247        $tdm.get($actor_name)
248            .and_then(|x| x.specifics.$access_func().ok())
249    };
250}
251#[macro_export]
252macro_rules! get_annos_from_tdm {
253    ($actor_name:expr, $tdm:expr, $current_file_path:expr, $access_func:ident) => {
254        $crate::get_specifics_from_tdm!($actor_name, $tdm, $access_func)
255            .and_then(|d| d.get_annos($current_file_path))
256    };
257}
258
259#[macro_export]
260macro_rules! get_labelinfo_from_tdm {
261    ($actor_name:expr, $tdm:expr,  $access_func:ident) => {
262        $crate::get_specifics_from_tdm!($actor_name, $tdm, $access_func).map(|d| d.label_info())
263    };
264}