From e3fe78ec5c6a75ff81d90188ce3df28b34fa288c Mon Sep 17 00:00:00 2001 From: Ruben van de Ven Date: Mon, 7 Jul 2025 20:08:11 +0200 Subject: [PATCH] WIP: clipping mask drawing (with glitch) --- src/bin/render_lines_gui.rs | 99 +++++++++++++++++++++++++++++++++++-- 1 file changed, 96 insertions(+), 3 deletions(-) diff --git a/src/bin/render_lines_gui.rs b/src/bin/render_lines_gui.rs index 86a0eaf..ade9722 100644 --- a/src/bin/render_lines_gui.rs +++ b/src/bin/render_lines_gui.rs @@ -20,6 +20,7 @@ use zmq::Socket; use std::sync::{mpsc, Arc}; use std::time::{Instant, Duration}; use std::collections::HashMap; +use std::cmp::{Ordering, min}; use serde::{Serialize,Deserialize}; use nannou::winit::dpi::PhysicalPosition; @@ -963,10 +964,19 @@ fn view_laser_preview(app: &App, model: &GuiModel, frame: Frame) { .w(win_rect.w()); // 3. clipping mask + its anchor points - let clip_points: Vec<[f32;2]> = Corner::in_laser_space().iter().map(|p| { + + let clip_points: Vec<[f32;2]> = config.filters.clip.mask.iter().map(|p| { [p[0] * hw, p[1] * hh] }).collect(); + for point in clip_points.iter() { + // TODO: does not work? + draw.ellipse() + .x_y(point[0], point[1]) + .radius(1.) + .color(BLACK); + } + draw.polygon() .color(srgba(1.,1.,1.,0.)) .stroke(PINK) @@ -1021,6 +1031,8 @@ fn laser_preview_mouse_pressed(app: &App, model: &mut GuiModel, button: MouseBut return; } + let config = model.per_laser_config.get_mut(&dac_id).expect("Dac config unavailable"); + let half_w = LASER_PREVIEW_WIDTH / 2.; let half_h = LASER_PREVIEW_HEIGHT / 2.; @@ -1032,7 +1044,63 @@ fn laser_preview_mouse_pressed(app: &App, model: &mut GuiModel, button: MouseBut // return // } - // 1. check if empty. it not check if one point is close + // 1. Always min. 4 points. We need closest two. So sort first + let mask_points = &config.filters.clip.mask; + let point_distances: Vec<(usize, f32, [f32;2])> = mask_points + .iter() + .enumerate() + .map(|(i, &p)| { + (i, (laser_x - p[0]).powi(2) + (laser_y - p[1]).powi(2), p) + }) + .collect(); + // dbg!(&half_w, &half_h, &laser_x, &laser_y, &point_distances); + let (idx, dist_sq, closest_point) = point_distances.iter().min_by(|a,b| a.1.partial_cmp(&b.1).unwrap()).expect("No clipping points existing?"); + + // = point_distances; + // let (idx2, _, _) = point_distances.get(1).expect("No clipping points existing?"); + + // match_distance is in pixelspace. Convert to laser-space + if dist_sq.sqrt() <= (MATCH_DISTANCE / half_w) { + // 2a. if closest is within MATCH_DISTANCE. Select point for dragging + model.preview_dragging_point = Some(idx.clone()); + // println!("Closest point {:?} is within distance: {}", closest_point, dist_sq.sqrt()); + } else { + // 2b. if not, if close point is found, if point has neighbours (i.e. len of vec > 1), and find which of neighbours is closest. Insert point between these. Select new point + let prev_point = point_distances.get((idx + point_distances.len() -1) % point_distances.len()).expect("No prev neighbour?"); + let next_point = point_distances.get((idx+1) % point_distances.len()).expect("No next neighbour"); + + // select closest of prev/next + let (idx2, _, _closest_point2) = if prev_point.1 < next_point.1 { + prev_point + } else { + next_point + }; + + + // insert point + let instert_at = *min(idx, idx2); + + let new_point = [laser_x, laser_y]; + + config.filters.clip.mask.insert(instert_at, new_point); + model.preview_dragging_point = Some(instert_at); + + // println!("Closest point {:?} is too far: {}", closest_point, dist_sq.sqrt()); + } + + + + // if (app.mouse.x - c[0]).abs() < MATCH_DISTANCE && (app.mouse.y - c[1]).abs() < MATCH_DISTANCE { + // dbg!("close to corner! {:?}", &c); + // match i { + // 0 => selected = Some(Corner::TopLeft), + // 1 => selected = Some(Corner::TopRight), + // 2 => selected = Some(Corner::BottomRight), + // 3 => selected = Some(Corner::BottomLeft), + // _ => selected = None, + // } + // break; + // } // 2a. if closest point is within selection margin, select that item. // 2b. if not, if close point is found, if point has neighbours (i.e. len of vec > 1), and find which of neighbours is closest. Insert point between these. Select new point // 2c. if no closest point is found (thus Vec is empty), create a point under cursor. Select that new point. @@ -1044,13 +1112,36 @@ fn laser_preview_mouse_pressed(app: &App, model: &mut GuiModel, button: MouseBut fn laser_mouse_moved(app: &App, model: &mut GuiModel, pos: Point2) { + let dac_id = match &model.selected_stream { + None => return, + Some(d) => d, + }; + + let point_idx = match &model.preview_dragging_point { + None => return, + Some(d) => d, + }; + + + let half_w = LASER_PREVIEW_WIDTH / 2.; let half_h = LASER_PREVIEW_HEIGHT / 2.; let laser_x = app.mouse.x / half_w; let laser_y = app.mouse.y / half_h; + + + + // 0. Get config + let config = model.per_laser_config.get_mut(&dac_id).expect("Dac config unavailable"); + // 1. Move selected point to laser_x, laser_y + // config.filters.clip. + let point = config.filters.clip.mask.get_mut(*point_idx).unwrap(); + + *point = [laser_x, laser_y]; + } fn laser_mouse_released(_app: &App, model: &mut GuiModel, _button: MouseButton) { @@ -1166,6 +1257,8 @@ fn map_mouse_moved(_app: &App, model: &mut GuiModel, pos: Point2) { } +const MATCH_DISTANCE: f32 = 30.; // screen pixels + fn map_mouse_pressed(app: &App, model: &mut GuiModel, button: MouseButton) { if button != MouseButton::Left { // ignore @@ -1173,7 +1266,7 @@ fn map_mouse_pressed(app: &App, model: &mut GuiModel, button: MouseButton) { } if let Some(dac_id) = &model.selected_stream { - const MATCH_DISTANCE: f32 = 30.; // screen pixels + let config = model.per_laser_config.get(&dac_id).expect("Dac config unavailable");