Compare commits

...

2 commits

Author SHA1 Message Date
Ruben van de Ven
fa3dc1d104 Mask drawing + removing points. TODO: applying clip mask 2025-07-07 20:29:30 +02:00
Ruben van de Ven
e3fe78ec5c WIP: clipping mask drawing (with glitch) 2025-07-07 20:08:11 +02:00
2 changed files with 92 additions and 14 deletions

View file

@ -15,11 +15,13 @@ use serde_json::Result;
use trap_rust::trap::filters::PointFilters;
use trap_rust::trap::laser::{shape_rect, LaserPoints, LaserSpace, StreamSource, STREAM_SOURCES, TMP_DESK_CLUBMAX, Corner};
use trap_rust::trap::tracks::CoordinateSpace;
use trap_rust::trap::utils::closest_edge;
use trap_rust::trap::{laser::{python_cv_h_into_mat3, LaserModel, TMP_PYTHON_LASER_H, DacConfig}, tracks::{RenderableLines}};
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;
@ -927,7 +929,7 @@ fn view_laser_preview(app: &App, model: &GuiModel, frame: Frame) {
let draw = app.draw();
draw.background().color(DARKGRAY);
draw.background().color(BLACK);
let win = app.window_rect();
@ -963,12 +965,21 @@ 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(5.)
.stroke(WHITE);
}
draw.polygon()
.color(srgba(1.,1.,1.,0.))
.color(srgba(1.,1.,1.,3.))
.stroke(PINK)
.stroke_weight(thickness)
.join_round()
@ -1015,11 +1026,8 @@ fn laser_preview_mouse_pressed(app: &App, model: &mut GuiModel, button: MouseBut
Some(d) => d,
};
if button != MouseButton::Left {
// ignore
// TODO: right click remove point within Margin
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,11 +1040,55 @@ 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
// 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.
// 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) {
if button == MouseButton::Left {
model.preview_dragging_point = Some(*idx);
}
if button == MouseButton::Right {
// require minimum of three corners for clipping
// (makes calculations/assumptions easier)
// so don't remove if too little
if config.filters.clip.mask.len() > 3 {
config.filters.clip.mask.remove(*idx);
}
}
// 2a. if closest is within MATCH_DISTANCE. Select point for dragging
} else {
if button == MouseButton::Left {
// 2b. if not, find closest edge
let insert_at = match closest_edge(&config.filters.clip.mask, [laser_x, laser_y]) {
Some(idx) => (idx + 1) % config.filters.clip.mask.len(),
None => return,
};
// insert point
// let instert_at = *min(idx, idx2);
let new_point = [laser_x, laser_y];
config.filters.clip.mask.insert(insert_at % config.filters.clip.mask.len(), new_point);
model.preview_dragging_point = Some(insert_at);
}
}
@ -1044,13 +1096,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 +1241,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 +1250,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");

View file

@ -10,4 +10,5 @@ pub mod tracks;
pub mod shapes;
pub mod laser;
pub mod filters;
pub mod filters;
pub mod utils;