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