1use crate::drawme::{Annotation, UpdateImage, UpdateTmpAnno};
2use crate::meta_data::MetaData;
3use crate::result::trace_ok_err;
4use crate::tools::{add_tools_initial_data, get_visible_inactive_names};
5use crate::tools_data::annotations::{ClipboardData, InstanceAnnotations};
6use crate::tools_data::predictive_labeling::PredictiveLabelingData;
7use crate::tools_data::{
8 self, vis_from_lfoption, AccessInstanceData, LabelInfo, ToolSpecifics, ToolsData, ToolsDataMap,
9};
10use crate::types::ViewImage;
11use crate::util::Visibility;
12use crate::{image_util, InstanceAnnotate, UpdatePermAnnos, UpdateView};
13use image::DynamicImage;
14use rvimage_domain::{BbF, RvError, RvResult, ShapeF, ShapeI};
15use std::path::Path;
16use std::{fmt::Debug, mem};
17
18pub(super) fn get<'a>(
19 world: &'a World,
20 actor: &'static str,
21 error_msg: &'a str,
22) -> RvResult<&'a ToolsData> {
23 world
24 .data
25 .tools_data_map
26 .get(actor)
27 .ok_or_else(|| RvError::new(error_msg))
28}
29pub fn get_specific<T>(
30 f: impl Fn(&ToolSpecifics) -> RvResult<&T>,
31 data: RvResult<&ToolsData>,
32) -> Option<&T> {
33 trace_ok_err(data.map(|d| &d.specifics).and_then(f))
34}
35pub(super) fn get_mut<'a>(
36 world: &'a mut World,
37 actor: &'static str,
38 error_msg: &'a str,
39) -> RvResult<&'a mut ToolsData> {
40 world
41 .data
42 .tools_data_map
43 .get_mut(actor)
44 .ok_or_else(|| RvError::new(error_msg))
45}
46pub fn get_specific_mut<T>(
47 f_data_access: impl FnMut(&mut ToolSpecifics) -> RvResult<&mut T>,
48 data: RvResult<&mut ToolsData>,
49) -> Option<&mut T> {
50 trace_ok_err(data.map(|d| &mut d.specifics).and_then(f_data_access))
51}
52
53pub trait MetaDataAccess {
55 fn get_core_options(world: &World) -> Option<&tools_data::Options>;
56 fn get_core_options_mut(world: &mut World) -> Option<&mut tools_data::Options>;
57 fn get_track_changes_str(world: &World) -> Option<&'static str>;
58 fn get_label_info(world: &World) -> Option<&LabelInfo>;
59 fn get_label_info_mut(world: &mut World) -> Option<&mut LabelInfo>;
60 fn get_predictive_labeling_data(world: &World) -> Option<&PredictiveLabelingData>;
61 fn get_predictive_labeling_data_mut(world: &mut World) -> Option<&mut PredictiveLabelingData>;
62}
63
64#[macro_export]
65macro_rules! tools_data_accessors {
66 ($actor_name:expr, $missing_data_msg:expr, $data_module:ident, $data_type:ident, $data_func:ident, $data_func_mut:ident) => {
67 #[allow(unused)]
68 pub(super) fn get_data(
69 world: &World,
70 ) -> rvimage_domain::RvResult<&$crate::tools_data::ToolsData> {
71 $crate::world::get(world, $actor_name, $missing_data_msg)
72 }
73 #[allow(unused)]
74 pub fn get_specific(
75 world: &World,
76 ) -> Option<&$crate::tools_data::$data_module::$data_type> {
77 $crate::world::get_specific($crate::tools_data::$data_func, get_data(world))
78 }
79 pub(super) fn get_data_mut(
80 world: &mut World,
81 ) -> rvimage_domain::RvResult<&mut $crate::tools_data::ToolsData> {
82 $crate::world::get_mut(world, $actor_name, $missing_data_msg)
83 }
84 pub fn get_specific_mut(
85 world: &mut World,
86 ) -> Option<&mut $crate::tools_data::$data_module::$data_type> {
87 $crate::world::get_specific_mut($crate::tools_data::$data_func_mut, get_data_mut(world))
88 }
89 };
90}
91#[macro_export]
92macro_rules! tools_data_accessors_objects {
93 ($actor_name:expr, $missing_data_msg:expr, $data_module:ident, $data_type:ident, $data_func:ident, $data_func_mut:ident) => {
94 pub(super) fn get_options(world: &World) -> Option<&$crate::tools_data::$data_module::Options> {
95 get_specific(world).map(|d| &d.options)
96 }
97 pub fn get_options_mut(world: &mut World) -> Option<&mut $crate::tools_data::$data_module::Options> {
98 get_specific_mut(world).map(|d| &mut d.options)
99 }
100 pub(super) fn get_track_changes_str(world: &World) -> Option<&'static str> {
101 lazy_static::lazy_static! {
102 static ref TRACK_CHANGE_STR: String = $crate::tools::core::make_track_changes_str($actor_name);
103 };
104 let track_changes =
105 get_options(world).map(|o| o.core.track_changes) == Some(true);
106 $crate::util::wrap_if(&TRACK_CHANGE_STR, track_changes)
107 }
108
109 pub fn get_label_info(world: &World) -> Option<&LabelInfo> {
110 get_specific(world).map(|d| &d.label_info)
111 }
112 pub(super) fn get_instance_label_display(world: &World) -> $crate::tools_data::InstanceLabelDisplay {
113 get_options(world).map(|d| d.core.instance_label_display).unwrap_or_default()
114 }
115
116 pub(super) struct DataAccessors;
118 impl $crate::world::MetaDataAccess for DataAccessors {
119 fn get_core_options(world: &World) -> Option<&$crate::tools_data::Options> {
120 get_options(world).map(|o| &o.core)
121 }
122 fn get_core_options_mut(world: &mut World) -> Option<&mut $crate::tools_data::Options> {
123 get_options_mut(world).map(|o| &mut o.core)
124 }
125 fn get_track_changes_str(world: &World) -> Option<&'static str> {
126 get_track_changes_str(world)
127 }
128 fn get_label_info(world: &World) -> Option<&LabelInfo> {
129 get_label_info(world)
130 }
131 fn get_label_info_mut(world: &mut World) -> Option<&mut LabelInfo> {
132 get_specific_mut(world).map(|d| &mut d.label_info)
133 }
134 fn get_predictive_labeling_data(world: &World) -> Option<&$crate::tools_data::predictive_labeling::PredictiveLabelingData> {
135 get_specific(world).map(|d| &d.predictive_labeling_data)
136 }
137 fn get_predictive_labeling_data_mut(world: &mut World) -> Option<&mut $crate::tools_data::predictive_labeling::PredictiveLabelingData> {
138 get_specific_mut(world).map(|d| &mut d.predictive_labeling_data)
139 }
140 }
141
142 pub(super) fn get_visible(world: &World) -> Visibility {
143 let visible = get_options(world).map(|o| o.core.visible) == Some(true);
144 vis_from_lfoption(get_label_info(world), visible)
145 }
146 pub(super) fn set_visible(world: &mut World) {
147 let options_mut = get_options_mut(world);
148 if let Some(options_mut) = options_mut {
149 options_mut.core.visible = true;
150 }
151 let vis = get_visible(world);
152 world.request_redraw_annotations($actor_name, vis);
153 }
154 };
155}
156#[macro_export]
157macro_rules! world_annotations_accessor {
158 ($actor_name:expr, $access_func:ident, $error_msg:expr, $annotations_type:ty) => {
159 pub(super) fn get_annos_(
160 world: &World,
161 is_no_anno_fine: bool,
162 ) -> Option<&$annotations_type> {
163 if let Some(current_file_path) = world.data.meta_data.file_path_relative() {
164 let res = $crate::get_annos_from_tdm!(
165 $actor_name,
166 &world.data.tools_data_map,
167 current_file_path,
168 $access_func
169 );
170 if res.is_none() && !is_no_anno_fine {
171 tracing::error!("{}", $error_msg);
172 }
173 res
174 } else {
175 None
176 }
177 }
178 #[allow(unused)]
179 pub fn get_annos(world: &World) -> Option<&$annotations_type> {
180 get_annos_(world, false)
181 }
182 #[allow(unused)]
183 pub fn get_annos_if_some(world: &World) -> Option<&$annotations_type> {
184 get_annos_(world, true)
185 }
186 };
187}
188#[macro_export]
189macro_rules! annotations_accessor_mut {
190 ($actor_name:expr, $access_func:ident, $error_msg:expr, $annotations_type:ty) => {
191 pub(super) fn get_annos_mut_(
192 world: &mut World,
193 is_no_anno_fine: bool,
194 ) -> Option<&mut $annotations_type> {
195 if let Some(current_file_path) = world.data.meta_data.file_path_relative() {
196 let shape_initial = world.shape_orig();
197 let res = world
198 .data
199 .tools_data_map
200 .get_mut($actor_name)
201 .and_then(|x| x.specifics.$access_func().ok())
202 .and_then(|d| d.get_annos_mut(¤t_file_path, shape_initial));
203 if res.is_none() {
204 tracing::error!("{}", $error_msg);
205 }
206 res
207 } else {
208 if !is_no_anno_fine {
209 tracing::error!("could not find filepath in meta data")
210 };
211 None
212 }
213 }
214 pub fn get_annos_mut(world: &mut World) -> Option<&mut $annotations_type> {
215 let is_no_anno_fine = world.data.meta_data.flags.is_file_list_empty == Some(true);
216 get_annos_mut_(world, is_no_anno_fine)
217 }
218 pub fn use_currentimageshape_for_annos(world: &mut World) {
219 get_annos_mut(world);
224 }
225 };
226}
227
228pub trait InstanceAnnoAccess<T>
229where
230 T: InstanceAnnotate,
231{
232 fn get_annos(world: &World) -> Option<&InstanceAnnotations<T>>;
233 fn get_annos_mut(world: &mut World) -> Option<&mut InstanceAnnotations<T>>;
234 fn get_clipboard(world: &World) -> Option<&ClipboardData<T>>;
235 fn set_clipboard(world: &mut World, clipboard: Option<ClipboardData<T>>);
236}
237#[macro_export]
238macro_rules! instance_annotations_accessor {
239 ($annotations_type:ty) => {
240 pub(super) struct InstanceAnnoAccessors;
241 impl $crate::world::InstanceAnnoAccess<$annotations_type> for InstanceAnnoAccessors {
242 fn get_annos(world: &World) -> Option<&$crate::tools_data::annotations::InstanceAnnotations<$annotations_type>> {
243 get_annos(world)
244 }
245 fn get_annos_mut(
246 world: &mut World,
247 ) -> Option<&mut $crate::tools_data::annotations::InstanceAnnotations<$annotations_type>> {
248 get_annos_mut(world)
249 }
250 fn get_clipboard(
251 world: &World,
252 ) -> Option<&$crate::tools_data::annotations::ClipboardData<$annotations_type>> {
253 get_specific(world).and_then(|d| d.clipboard.as_ref())
254 }
255 fn set_clipboard(
256 world: &mut World,
257 clipboard: Option<$crate::tools_data::annotations::ClipboardData<$annotations_type>>,
258 ) {
259 let specific_data = get_specific_mut(world);
260 if let Some(d) = specific_data {
261 d.clipboard = clipboard;
262 }
263 }
264 }
265 };
266}
267
268#[derive(Clone, Default, PartialEq)]
269pub struct DataRaw {
270 im_background: DynamicImage,
271 ui_image_rect: Option<ShapeF>,
272 pub meta_data: MetaData,
273 pub tools_data_map: ToolsDataMap,
274}
275
276impl DataRaw {
277 #[must_use]
278 pub fn new(
279 im_background: DynamicImage,
280 tools_data_map: ToolsDataMap,
281 meta_data: MetaData,
282 ui_image_rect: Option<ShapeF>,
283 ) -> Self {
284 DataRaw {
285 im_background,
286 ui_image_rect,
287 meta_data,
288 tools_data_map,
289 }
290 }
291
292 #[must_use]
293 pub fn im_background(&self) -> &DynamicImage {
294 &self.im_background
295 }
296 pub fn im_background_mut(&mut self) -> &mut DynamicImage {
297 &mut self.im_background
298 }
299
300 pub fn set_image_rect(&mut self, ui_image_rect: Option<ShapeF>) {
301 self.ui_image_rect = ui_image_rect;
302 }
303
304 pub fn apply<FI>(&mut self, mut f_i: FI)
305 where
306 FI: FnMut(DynamicImage) -> DynamicImage,
307 {
308 self.im_background = f_i(mem::take(&mut self.im_background));
309 }
310
311 #[must_use]
312 pub fn shape(&self) -> ShapeI {
313 ShapeI::from_im(&self.im_background)
314 }
315
316 #[must_use]
317 pub fn bg_to_uncropped_view(&self) -> ViewImage {
318 image_util::orig_to_0_255(&self.im_background, &None)
319 }
320}
321
322impl Debug for DataRaw {
323 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
324 write!(
325 f,
326 "\nshape {:?}\ntools data {:?}",
327 self.shape(),
328 self.tools_data_map,
329 )
330 }
331}
332
333fn evaluate_visibility(
334 visibility: Visibility,
335 tool_name: &str,
336 data: &DataRaw,
337) -> Option<Vec<Annotation>> {
338 match (
339 visibility,
340 &data.meta_data.file_path_relative(),
341 data.tools_data_map.get(tool_name),
342 ) {
343 (Visibility::All, Some(file_path_relative), Some(td)) => {
344 td.specifics.to_annotations_view(file_path_relative, None)
345 }
346 (Visibility::Only(idx), Some(file_path), Some(td)) => {
347 td.specifics.to_annotations_view(file_path, Some(idx))
348 }
349 (Visibility::None, _, _) => Some(vec![]),
350 _ => None,
351 }
352}
353#[derive(Clone, Default)]
355pub struct World {
356 pub update_view: UpdateView,
357 pub data: DataRaw,
358 zoom_box: Option<BbF>,
360}
361
362impl World {
363 #[must_use]
364 pub fn new(ims_raw: DataRaw, zoom_box: Option<BbF>) -> Self {
365 let update_view = UpdateView::new(&ims_raw, zoom_box);
366 let mut world = Self {
367 data: ims_raw,
368 zoom_box,
369 update_view,
370 };
371 world.data.tools_data_map =
372 add_tools_initial_data(mem::take(&mut world.data.tools_data_map));
373 world
374 }
375 pub fn reset_updateview(&mut self) {
376 self.update_view = UpdateView::new(&self.data, self.zoom_box);
377 }
378
379 #[must_use]
380 pub fn ui_image_rect(&self) -> Option<ShapeF> {
381 self.data.ui_image_rect
382 }
383
384 pub fn request_redraw_annotations(&mut self, tool_name: &str, visibility_active: Visibility) {
389 let visible_inactive_tools = self
390 .data
391 .tools_data_map
392 .get(tool_name)
393 .map(|td| td.visible_inactive_tools.clone());
394 let tool_names_inactive = get_visible_inactive_names(tool_name);
395 let mut annos_inactive: Option<Vec<Annotation>> = None;
396 if let Some(visible_inactive_tools) = visible_inactive_tools {
397 for (tool_name_inactive, show) in tool_names_inactive
398 .iter()
399 .zip(visible_inactive_tools.iter())
400 {
401 let vli = self.data.tools_data_map.get(tool_name_inactive).map(|td| {
402 match &td.specifics {
403 tools_data::ToolSpecifics::Bbox(bbox_data) => {
404 (bbox_data.options.core.visible, bbox_data.label_info())
405 }
406 tools_data::ToolSpecifics::Brush(brush_data) => {
407 (brush_data.options.core.visible, brush_data.label_info())
408 }
409 _ => {
410 panic!("tool {tool_name_inactive} does not redraw annotations ");
411 }
412 }
413 });
414 let visibility_inactive = if let Some((visible, label_info)) = vli {
415 vis_from_lfoption(Some(label_info), visible)
416 } else {
417 Visibility::All
418 };
419 if show && visibility_active != Visibility::None {
420 if let Some(annos) = &mut annos_inactive {
421 let annos_inner = evaluate_visibility(
422 visibility_inactive,
423 tool_name_inactive,
424 &self.data,
425 );
426 if let Some(annos_inner) = annos_inner {
427 annos.extend(annos_inner);
428 }
429 } else {
430 annos_inactive = evaluate_visibility(
431 visibility_inactive,
432 tool_name_inactive,
433 &self.data,
434 );
435 }
436 }
437 }
438 }
439 let annos_active = evaluate_visibility(visibility_active, tool_name, &self.data);
440 if let Some(annos_active) = annos_active {
441 if let Some(annos_inactive) = annos_inactive {
442 let mut annos = annos_active;
443 annos.extend(annos_inactive);
444 self.update_view.perm_annos = UpdatePermAnnos::Yes(annos);
445 } else {
446 self.update_view.perm_annos = UpdatePermAnnos::Yes(annos_active);
447 }
448 } else if let Some(annos_inactive) = annos_inactive {
449 self.update_view.perm_annos = UpdatePermAnnos::Yes(annos_inactive);
450 }
451 }
452
453 pub fn request_redraw_tmp_anno(&mut self, anno: Annotation) {
454 self.update_view.tmp_annos = UpdateTmpAnno::Yes(anno);
455 }
456
457 pub fn stop_tmp_anno(&mut self) {
458 self.update_view.tmp_annos = UpdateTmpAnno::No;
459 }
460
461 pub fn request_redraw_image(&mut self) {
462 if self.data.meta_data.file_path_relative().is_some() {
463 self.update_view.image = UpdateImage::Yes(self.data.bg_to_uncropped_view());
464 }
465 }
466
467 #[must_use]
469 pub fn from_real_im(
470 im: DynamicImage,
471 tools_data: ToolsDataMap,
472 ui_image_rect: Option<ShapeF>,
473 file_path: Option<String>,
474 prj_path: &Path,
475 file_selected_idx: Option<usize>,
476 ) -> Self {
477 let meta_data = match (file_path, file_selected_idx) {
478 (Some(fp), Some(fsidx)) => MetaData::from_filepath(fp, fsidx, prj_path),
479 _ => MetaData::default(),
480 };
481 Self::new(DataRaw::new(im, tools_data, meta_data, ui_image_rect), None)
482 }
483
484 #[must_use]
485 pub fn shape_orig(&self) -> ShapeI {
486 self.data.shape()
487 }
488
489 pub fn set_zoom_box(&mut self, zoom_box: Option<BbF>) {
490 let mut set_zb = || {
491 let zoom_box =
492 zoom_box.map(|zb| BbF::new_fit_to_image(zb.x, zb.y, zb.w, zb.h, self.shape_orig()));
493 self.zoom_box = zoom_box;
494 self.update_view = UpdateView::from_zoombox(zoom_box);
495 };
496 if let Some(zb) = zoom_box {
497 if zb.h > 1.0 && zb.w > 1.0 {
498 set_zb();
499 }
500 } else {
501 set_zb();
502 }
503 }
504
505 #[must_use]
506 pub fn zoom_box(&self) -> &Option<BbF> {
507 &self.zoom_box
508 }
509
510 pub fn set_image_rect(&mut self, ui_image_rect: Option<ShapeF>) {
511 self.data.set_image_rect(ui_image_rect);
512 }
513 pub fn set_background_image(&mut self, image: DynamicImage) {
514 if ShapeI::from_im(&image) != self.shape_orig() {
515 self.zoom_box = None;
516 }
517 self.data.im_background = image;
518 }
519}
520impl Debug for World {
521 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
522 write!(f, "\nims_raw {:?}", &self.data)
523 }
524}
525
526#[cfg(test)]
527fn rgba_at(i: usize, im: &ViewImage) -> [u8; 4] {
528 let x = (i % im.width() as usize) as u32;
529 let y = (i / im.width() as usize) as u32;
530 let rgb = im.get_pixel(x, y).0;
531 let rgb_changed = rgb;
532 [rgb_changed[0], rgb_changed[1], rgb_changed[2], 0xff]
533}
534#[cfg(test)]
535use image::Rgb;
536
537#[test]
538fn test_rgba() {
539 let mut im_test = ViewImage::new(64, 64);
540 im_test.put_pixel(0, 0, Rgb([23, 23, 23]));
541 assert_eq!(rgba_at(0, &im_test), [23, 23, 23, 255]);
542 im_test.put_pixel(0, 1, Rgb([23, 23, 23]));
543 assert_eq!(rgba_at(64, &im_test), [23, 23, 23, 255]);
544 im_test.put_pixel(7, 11, Rgb([23, 23, 23]));
545 assert_eq!(rgba_at(11 * 64 + 7, &im_test), [23, 23, 23, 255]);
546}