added a more robust box selection algorithm that needs testing
This commit is contained in:
parent
bc5d2bc84e
commit
f6b9c50e7e
3 changed files with 83 additions and 35 deletions
|
@ -187,7 +187,6 @@ async fn listen_to_messages(
|
|||
Ok(None) => {
|
||||
info!("Recieved an empty message from the remote computer: Aborting");
|
||||
break;
|
||||
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Got an error on while recieving from remote computer: {e}");
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
use std::sync::{Arc, Mutex};
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
use gtk::{
|
||||
gdk::Paintable,
|
||||
|
@ -6,10 +9,10 @@ use gtk::{
|
|||
AspectFrame, Box, DrawingArea, EventControllerMotion, GestureClick, Label, Overlay, Picture,
|
||||
};
|
||||
|
||||
use tracing::info;
|
||||
|
||||
use crate::remote_sources::TrackerState;
|
||||
|
||||
use super::NormalizedBoxCoords;
|
||||
|
||||
pub struct LiveViewPanel {
|
||||
top_level: gtk::Box,
|
||||
|
||||
|
@ -59,7 +62,7 @@ impl LiveViewPanel {
|
|||
let move_handler = EventControllerMotion::builder()
|
||||
.propagation_limit(gtk::PropagationLimit::SameNative)
|
||||
.build();
|
||||
|
||||
|
||||
let tracker_state_2 = tracker_state.clone();
|
||||
|
||||
let handler_picture = webcam_picture.clone();
|
||||
|
@ -110,20 +113,9 @@ impl LiveViewPanel {
|
|||
let y_coord = y_coord as f32 / y_size as f32;
|
||||
|
||||
if let Ok(mut ts) = tracker_state.lock() {
|
||||
let mut select: Option<u32> = None;
|
||||
for nb in ts.identity_boxes.iter() {
|
||||
if nb.x1 < x_coord as f32
|
||||
&& nb.y1 < y_coord as f32
|
||||
&& nb.x2 > x_coord as f32
|
||||
&& nb.y2 > y_coord as f32
|
||||
{
|
||||
select = Some(nb.id);
|
||||
}
|
||||
}
|
||||
if let Some(new_id) = select {
|
||||
ts.tracking_id = new_id;
|
||||
}
|
||||
ts.highlighted_id = calc_box_under_mouse(&ts.identity_boxes, x_coord, y_coord);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn motion_callback(
|
||||
|
@ -134,21 +126,13 @@ impl LiveViewPanel {
|
|||
) {
|
||||
let x_size = overlay.size(gtk::Orientation::Horizontal);
|
||||
let y_size = overlay.size(gtk::Orientation::Vertical);
|
||||
|
||||
let x_coord = x_coord as f32 / x_size as f32;
|
||||
let y_coord = y_coord as f32 / y_size as f32;
|
||||
|
||||
if let Ok(mut ts) = tracker_state.lock() {
|
||||
let mut highlighted_id: Option<u32> = None;
|
||||
for nb in ts.identity_boxes.iter() {
|
||||
if nb.x1 < x_coord as f32
|
||||
&& nb.y1 < y_coord as f32
|
||||
&& nb.x2 > x_coord as f32
|
||||
&& nb.y2 > y_coord as f32
|
||||
{
|
||||
highlighted_id = Some(nb.id);
|
||||
}
|
||||
if let Some(v) = calc_box_under_mouse(&ts.identity_boxes, x_coord, y_coord) {
|
||||
ts.tracking_id = v;
|
||||
}
|
||||
ts.highlighted_id = highlighted_id;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -164,3 +148,65 @@ impl LiveViewPanel {
|
|||
self.picture.set_paintable(Some(new_paintable));
|
||||
}
|
||||
}
|
||||
|
||||
fn calc_box_under_mouse(boxes: &Vec<NormalizedBoxCoords>, x_coord: f32, y_coord: f32) -> Option<u32> {
|
||||
let mut mouse_over: Vec<NormalizedBoxCoords> = vec![];
|
||||
|
||||
for nb in boxes.iter() {
|
||||
if nb.x1 < x_coord as f32
|
||||
&& nb.y1 < y_coord as f32
|
||||
&& nb.x2 > x_coord as f32
|
||||
&& nb.y2 > y_coord as f32
|
||||
{
|
||||
mouse_over.push(nb.clone());
|
||||
}
|
||||
}
|
||||
if mouse_over.len() == 1 {
|
||||
// the length is one, why would the unwrap fail
|
||||
let new_id = mouse_over.first().expect("Length one vec had no first");
|
||||
return Some(new_id.id);
|
||||
} else if mouse_over.len() > 1 {
|
||||
let mut x_coords = mouse_over
|
||||
.iter()
|
||||
.flat_map(|b| [b.x1, b.x2])
|
||||
.collect::<Vec<f32>>();
|
||||
x_coords.sort_by(|a, b| a.partial_cmp(b).unwrap());
|
||||
|
||||
let mid = x_coords.len() / 2;
|
||||
let median_two_x = &x_coords[mid - 1..mid + 1];
|
||||
|
||||
let mut y_coords = mouse_over
|
||||
.iter()
|
||||
.flat_map(|b| [b.y1, b.y2])
|
||||
.collect::<Vec<f32>>();
|
||||
y_coords.sort_by(|a, b| a.partial_cmp(b).unwrap());
|
||||
let median_two_y = &y_coords[mid - 1..mid + 1];
|
||||
|
||||
let overlap_area =
|
||||
(median_two_x[1] - median_two_x[0]) * (median_two_y[1] - median_two_y[0]);
|
||||
|
||||
mouse_over.sort_by(|a, b| {
|
||||
// a is valid for cutting in line if the
|
||||
// overlap area is greater than 75% of a's area
|
||||
let a_overlap = overlap_area >= 0.75 * a.area();
|
||||
let b_overlap = overlap_area >= 0.75 * b.area();
|
||||
|
||||
match (a_overlap, b_overlap) {
|
||||
// if the areas are not valid for cutting in line or both are
|
||||
// do the sorting based on the id, and let the hover affect
|
||||
// force the user to decide
|
||||
(true, true) | (false, false) => {
|
||||
if a.id > b.id {
|
||||
Ordering::Greater
|
||||
} else {
|
||||
Ordering::Less
|
||||
}
|
||||
}
|
||||
(false, true) => Ordering::Less,
|
||||
(true, false) => Ordering::Greater,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
mouse_over.iter().map(|x| x.id).collect::<Vec<u32>>().first().copied()
|
||||
}
|
|
@ -30,7 +30,7 @@ pub enum GuiUpdate {
|
|||
UpdatePaintable(gstreamer::Element),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct BoxCoords {
|
||||
pub id: u32,
|
||||
pub x1: u32,
|
||||
|
@ -49,7 +49,7 @@ impl Display for BoxCoords {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct NormalizedBoxCoords {
|
||||
pub id: u32,
|
||||
pub x1: f32,
|
||||
|
@ -68,6 +68,10 @@ impl NormalizedBoxCoords {
|
|||
y2: (self.y2 * height as f32) as u32,
|
||||
}
|
||||
}
|
||||
|
||||
fn area(&self) -> f32 {
|
||||
(self.x2 - self.x1) * (self.y2 - self.y1)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for NormalizedBoxCoords {
|
||||
|
@ -101,7 +105,7 @@ pub fn on_activate(app: &Application) {
|
|||
};
|
||||
|
||||
let menubar = gio::Menu::new();
|
||||
menubar.append_submenu(Some("Connections"), &connections_menu);
|
||||
menubar.append_submenu(Some("Settings"), &connections_menu);
|
||||
|
||||
menubar
|
||||
};
|
||||
|
@ -128,10 +132,10 @@ pub fn build_ui(app: &Application, config: Arc<RwLock<AppConfig>>, runtime: Hand
|
|||
.build();
|
||||
|
||||
let rt = runtime.clone();
|
||||
let config_modal_config = config.clone();
|
||||
let connections_modal_config = config.clone();
|
||||
let connections_activate = gio::ActionEntry::builder("connections")
|
||||
.activate(clone!(@weak window => move |app: >k::Application, _, _| {
|
||||
let connections_modal = settings_modal::ConnectionsModal::new(&app, &window, &rt, &config_modal_config);
|
||||
let connections_modal = settings_modal::ConnectionsModal::new(&app, &window, &rt, &connections_modal_config);
|
||||
|
||||
connections_modal.window.present();
|
||||
}))
|
||||
|
@ -169,7 +173,6 @@ pub fn build_ui(app: &Application, config: Arc<RwLock<AppConfig>>, runtime: Hand
|
|||
let control_panel = ControlPanel::new(tracker_state.clone());
|
||||
control_panel.connect_button_callbacks(to_mec.clone());
|
||||
|
||||
// left_box.append(&conn_status_label);
|
||||
left_box.append(control_panel.get_top_level());
|
||||
|
||||
main_box.append(&left_box);
|
||||
|
|
Loading…
Reference in a new issue