WIP: clip mask drawing
This commit is contained in:
parent
65acde713f
commit
9ef4c6745d
3 changed files with 136 additions and 48 deletions
|
@ -13,7 +13,7 @@ use nannou_laser::DacId;
|
||||||
use nannou_laser::{self as laser};
|
use nannou_laser::{self as laser};
|
||||||
use serde_json::Result;
|
use serde_json::Result;
|
||||||
use trap_rust::trap::filters::PointFilters;
|
use trap_rust::trap::filters::PointFilters;
|
||||||
use trap_rust::trap::laser::{shape_rect, LaserPoints, LaserSpace, StreamSource, STREAM_SOURCES, TMP_DESK_CLUBMAX};
|
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::tracks::CoordinateSpace;
|
||||||
use trap_rust::trap::{laser::{python_cv_h_into_mat3, LaserModel, TMP_PYTHON_LASER_H, DacConfig}, tracks::{RenderableLines}};
|
use trap_rust::trap::{laser::{python_cv_h_into_mat3, LaserModel, TMP_PYTHON_LASER_H, DacConfig}, tracks::{RenderableLines}};
|
||||||
use zmq::Socket;
|
use zmq::Socket;
|
||||||
|
@ -50,28 +50,7 @@ pub struct StreamConfig{
|
||||||
type StreamConfigMap = HashMap<DacId, StreamConfig>;
|
type StreamConfigMap = HashMap<DacId, StreamConfig>;
|
||||||
type StreamMap = HashMap<DacId, laser::FrameStream<LaserModel>>;
|
type StreamMap = HashMap<DacId, laser::FrameStream<LaserModel>>;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
enum Corner{
|
|
||||||
TopLeft,
|
|
||||||
TopRight,
|
|
||||||
BottomLeft,
|
|
||||||
BottomRight,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Corner {
|
|
||||||
pub fn in_laser_space() -> Vec<[f32; 2]>{
|
|
||||||
vec!([-1.,1.], [1.,1.], [-1.,-1.], [1., -1.])
|
|
||||||
}
|
|
||||||
|
|
||||||
fn index(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
Self::TopLeft => 0,
|
|
||||||
Self::TopRight => 1,
|
|
||||||
Self::BottomLeft => 2,
|
|
||||||
Self::BottomRight => 3,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct GuiModel {
|
struct GuiModel {
|
||||||
// A handle to the laser API used for spawning streams and detecting DACs.
|
// A handle to the laser API used for spawning streams and detecting DACs.
|
||||||
|
@ -98,6 +77,7 @@ struct GuiModel {
|
||||||
canvas_scale: f32,
|
canvas_scale: f32,
|
||||||
canvas_translate: Vec2,
|
canvas_translate: Vec2,
|
||||||
canvas_dragging_corner: Option<Corner>,
|
canvas_dragging_corner: Option<Corner>,
|
||||||
|
preview_dragging_point: Option<usize>,
|
||||||
// canvas_transform: Translation2D<f32, ScreenSpace, ScreenSpace>,
|
// canvas_transform: Translation2D<f32, ScreenSpace, ScreenSpace>,
|
||||||
// dragging: bool,
|
// dragging: bool,
|
||||||
}
|
}
|
||||||
|
@ -329,6 +309,8 @@ fn model(app: &App) -> GuiModel {
|
||||||
// .key_pressed(key_pressed)
|
// .key_pressed(key_pressed)
|
||||||
// .mouse_wheel(canvas_zoom)
|
// .mouse_wheel(canvas_zoom)
|
||||||
.mouse_pressed(laser_preview_mouse_pressed)
|
.mouse_pressed(laser_preview_mouse_pressed)
|
||||||
|
.mouse_released(laser_mouse_released)
|
||||||
|
.mouse_moved(laser_mouse_moved)
|
||||||
.view(view_laser_preview)
|
.view(view_laser_preview)
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -413,6 +395,7 @@ fn model(app: &App) -> GuiModel {
|
||||||
canvas_scale: 25.,
|
canvas_scale: 25.,
|
||||||
canvas_translate: Vec2::new(-300.,100.),
|
canvas_translate: Vec2::new(-300.,100.),
|
||||||
canvas_dragging_corner: None,
|
canvas_dragging_corner: None,
|
||||||
|
preview_dragging_point: None,
|
||||||
// canvas_transform: Transform2D
|
// canvas_transform: Transform2D
|
||||||
// dimming_factor: 1.,
|
// dimming_factor: 1.,
|
||||||
}
|
}
|
||||||
|
@ -935,6 +918,9 @@ fn view_line_canvas(app: &App, model: &GuiModel, frame: Frame) {
|
||||||
draw.to_frame(app, &frame).unwrap();
|
draw.to_frame(app, &frame).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const LASER_PREVIEW_WIDTH: f32 = 1024.;
|
||||||
|
const LASER_PREVIEW_HEIGHT: f32 = 1024.;
|
||||||
|
|
||||||
// preview the selected laser, to draw clip mask
|
// preview the selected laser, to draw clip mask
|
||||||
fn view_laser_preview(app: &App, model: &GuiModel, frame: Frame) {
|
fn view_laser_preview(app: &App, model: &GuiModel, frame: Frame) {
|
||||||
// get canvas to draw on
|
// get canvas to draw on
|
||||||
|
@ -945,8 +931,8 @@ fn view_laser_preview(app: &App, model: &GuiModel, frame: Frame) {
|
||||||
|
|
||||||
let win = app.window_rect();
|
let win = app.window_rect();
|
||||||
|
|
||||||
let w = 1024.;
|
let w = LASER_PREVIEW_WIDTH;
|
||||||
let h = 1024.;
|
let h = LASER_PREVIEW_HEIGHT;
|
||||||
let hh = h / 2.;
|
let hh = h / 2.;
|
||||||
let hw = w / 2.;
|
let hw = w / 2.;
|
||||||
|
|
||||||
|
@ -963,9 +949,12 @@ fn view_laser_preview(app: &App, model: &GuiModel, frame: Frame) {
|
||||||
},
|
},
|
||||||
Some(dac_id) => {
|
Some(dac_id) => {
|
||||||
// let stream = model.laser_streams.get(&dac_id); //.expect("Selected stream not found in configs");
|
// let stream = model.laser_streams.get(&dac_id); //.expect("Selected stream not found in configs");
|
||||||
|
|
||||||
|
// 1. get config for laser
|
||||||
let config = model.per_laser_config.get(&dac_id).expect("Selected stream not found in configs");
|
let config = model.per_laser_config.get(&dac_id).expect("Selected stream not found in configs");
|
||||||
|
|
||||||
draw.text(&format!("{:?}", dac_id))
|
// 2 draw identifier of laser
|
||||||
|
draw.text(&format!("{} {:?}", config.name, dac_id))
|
||||||
.h(win_rect.h())
|
.h(win_rect.h())
|
||||||
.font_size(10)
|
.font_size(10)
|
||||||
.align_text_bottom()
|
.align_text_bottom()
|
||||||
|
@ -973,6 +962,21 @@ fn view_laser_preview(app: &App, model: &GuiModel, frame: Frame) {
|
||||||
.color(WHITE)
|
.color(WHITE)
|
||||||
.w(win_rect.w());
|
.w(win_rect.w());
|
||||||
|
|
||||||
|
// 3. clipping mask + its anchor points
|
||||||
|
let clip_points: Vec<[f32;2]> = Corner::in_laser_space().iter().map(|p| {
|
||||||
|
[p[0] * hw, p[1] * hh]
|
||||||
|
}).collect();
|
||||||
|
|
||||||
|
draw.polygon()
|
||||||
|
.color(srgba(1.,1.,1.,0.))
|
||||||
|
.stroke(PINK)
|
||||||
|
.stroke_weight(thickness)
|
||||||
|
.join_round()
|
||||||
|
.points(clip_points);
|
||||||
|
|
||||||
|
|
||||||
|
// 4. current shape of the laser
|
||||||
|
|
||||||
|
|
||||||
let current_points: LaserPoints = (&model.current_lines).into();
|
let current_points: LaserPoints = (&model.current_lines).into();
|
||||||
let space = &model.current_lines.space;
|
let space = &model.current_lines.space;
|
||||||
|
@ -1001,32 +1005,57 @@ fn view_laser_preview(app: &App, model: &GuiModel, frame: Frame) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
draw.to_frame(app, &frame).unwrap();
|
draw.to_frame(app, &frame).unwrap();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn laser_preview_mouse_pressed(app: &App, _model: &mut GuiModel, button: MouseButton) {
|
fn laser_preview_mouse_pressed(app: &App, model: &mut GuiModel, button: MouseButton) {
|
||||||
|
let dac_id = match &model.selected_stream {
|
||||||
|
None => return,
|
||||||
|
Some(d) => d,
|
||||||
|
};
|
||||||
|
|
||||||
if button != MouseButton::Left {
|
if button != MouseButton::Left {
|
||||||
// ignore
|
// ignore
|
||||||
|
// TODO: right click remove point within Margin
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let half_w = (1024 / 2) as f32;
|
let half_w = LASER_PREVIEW_WIDTH / 2.;
|
||||||
let half_h = (1024 / 2) as f32;
|
let half_h = LASER_PREVIEW_HEIGHT / 2.;
|
||||||
|
|
||||||
let x = app.mouse.x / half_w;
|
let laser_x = app.mouse.x / half_w;
|
||||||
let y = app.mouse.y / half_h;
|
let laser_y = app.mouse.y / half_h;
|
||||||
|
|
||||||
if x > 1. || x < -1. || y > 1. || y < -1. {
|
// if x > 1. || x < -1. || y > 1. || y < -1. {
|
||||||
println!("Click outside of canvas: {} {}", x, y);
|
// println!("Click outside of canvas: {} {}", x, y);
|
||||||
return
|
// 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.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn laser_mouse_moved(app: &App, model: &mut GuiModel, pos: Point2) {
|
||||||
|
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;
|
||||||
|
|
||||||
|
// 1. Move selected point to laser_x, laser_y
|
||||||
|
}
|
||||||
|
|
||||||
|
fn laser_mouse_released(_app: &App, model: &mut GuiModel, _button: MouseButton) {
|
||||||
|
// deselect point
|
||||||
|
model.preview_dragging_point = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_grid(draw: &Draw, win: &Rect, step: f32, weight: f32) {
|
fn draw_grid(draw: &Draw, win: &Rect, step: f32, weight: f32) {
|
||||||
|
@ -1072,8 +1101,6 @@ fn style() -> egui::Style {
|
||||||
style
|
style
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mouse_moved(_app: &App, _model: &mut GuiModel, _pos: Point2) {
|
|
||||||
}
|
|
||||||
|
|
||||||
fn laser_corners_to_world(filters: &PointFilters) -> Vec<[f32;2]> {
|
fn laser_corners_to_world(filters: &PointFilters) -> Vec<[f32;2]> {
|
||||||
let corners_raw: Vec<[f32; 2]> = Corner::in_laser_space();
|
let corners_raw: Vec<[f32; 2]> = Corner::in_laser_space();
|
||||||
|
@ -1169,8 +1196,8 @@ fn map_mouse_pressed(app: &App, model: &mut GuiModel, button: MouseButton) {
|
||||||
match i {
|
match i {
|
||||||
0 => selected = Some(Corner::TopLeft),
|
0 => selected = Some(Corner::TopLeft),
|
||||||
1 => selected = Some(Corner::TopRight),
|
1 => selected = Some(Corner::TopRight),
|
||||||
2 => selected = Some(Corner::BottomLeft),
|
2 => selected = Some(Corner::BottomRight),
|
||||||
3 => selected = Some(Corner::BottomRight),
|
3 => selected = Some(Corner::BottomLeft),
|
||||||
_ => selected = None,
|
_ => selected = None,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use bevy::prelude::*; // for glam::f32::Mat3
|
use bevy::prelude::*; // for glam::f32::Mat3
|
||||||
|
|
||||||
use crate::trap::{laser::{apply_homography_matrix, LaserPoints}, tracks::CoordinateSpace};
|
use crate::trap::{laser::{apply_homography_matrix, Corner, LaserPoints}, tracks::CoordinateSpace};
|
||||||
|
|
||||||
use nannou_laser::{self as laser, Point};
|
use nannou_laser::{self as laser, Point};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -22,6 +22,12 @@ pub struct CropFilter {
|
||||||
pub enabled: bool
|
pub enabled: bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
pub struct ClipFilter {
|
||||||
|
pub enabled: bool,
|
||||||
|
pub mask: Vec<[f32; 2]>
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
pub struct DimFilter {
|
pub struct DimFilter {
|
||||||
pub intensity: f32
|
pub intensity: f32
|
||||||
|
@ -59,6 +65,7 @@ pub struct PointFilters{
|
||||||
pub scale: ScaleFilter,
|
pub scale: ScaleFilter,
|
||||||
pub pincushion: PincushionFilter,
|
pub pincushion: PincushionFilter,
|
||||||
pub crop: CropFilter,
|
pub crop: CropFilter,
|
||||||
|
pub clip: ClipFilter,
|
||||||
}
|
}
|
||||||
|
|
||||||
// list of enums deprecated in favour of struct
|
// list of enums deprecated in favour of struct
|
||||||
|
@ -128,6 +135,7 @@ impl Default for PointFilters {
|
||||||
scale: ScaleFilter { factor: 1. },
|
scale: ScaleFilter { factor: 1. },
|
||||||
pincushion: PincushionFilter{k_x: 0.,k_x2: 0., k_y: 0., k_y2: 0.},
|
pincushion: PincushionFilter{k_x: 0.,k_x2: 0., k_y: 0., k_y2: 0.},
|
||||||
crop: CropFilter{ enabled: true },
|
crop: CropFilter{ enabled: true },
|
||||||
|
clip: ClipFilter{ enabled: false, mask: Corner::in_laser_space() },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -146,8 +154,8 @@ impl Filter for HomographyFilter {
|
||||||
|
|
||||||
};
|
};
|
||||||
// also converts from world space to laser space (origin in center)
|
// also converts from world space to laser space (origin in center)
|
||||||
let s = 0xFFF as f32 / 2.;
|
// let s = 0xFFF as f32 / 2.;
|
||||||
let normalised_pos: [f32;2] = [new_position[0]/s - 1., new_position[1]/s - 1.];
|
// let normalised_pos: [f32;2] = [new_position[0]/s - 1., new_position[1]/s - 1.];
|
||||||
laser::Point {
|
laser::Point {
|
||||||
position: new_position,
|
position: new_position,
|
||||||
.. point.clone()
|
.. point.clone()
|
||||||
|
@ -322,7 +330,7 @@ impl Filter for CropFilter {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reverse(&self, points: &LaserPoints) -> LaserPoints{
|
fn reverse(&self, points: &LaserPoints) -> LaserPoints{
|
||||||
// we cannot really add points, can we
|
// we cannot really conjure up points, can we
|
||||||
return LaserPoints{
|
return LaserPoints{
|
||||||
points: points.points.clone(),
|
points: points.points.clone(),
|
||||||
space: points.space,
|
space: points.space,
|
||||||
|
@ -330,6 +338,36 @@ impl Filter for CropFilter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
impl Filter for ClipFilter {
|
||||||
|
|
||||||
|
fn apply(&self, points: &LaserPoints) -> LaserPoints {
|
||||||
|
if !self.enabled {
|
||||||
|
// don't modify if disabled
|
||||||
|
return LaserPoints{
|
||||||
|
points: points.points.clone(),
|
||||||
|
space: points.space,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
return LaserPoints{
|
||||||
|
points: points.points.clone(),
|
||||||
|
space: points.space,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reverse(&self, points: &LaserPoints) -> LaserPoints{
|
||||||
|
// we cannot really conjure up points, can we
|
||||||
|
return LaserPoints{
|
||||||
|
points: points.points.clone(),
|
||||||
|
space: points.space,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
fn change_brightness(points: &LaserPoints, intensity: f32) -> LaserPoints{
|
fn change_brightness(points: &LaserPoints, intensity: f32) -> LaserPoints{
|
||||||
let new_points = points.points.iter().map(|point| {
|
let new_points = points.points.iter().map(|point| {
|
||||||
let mut color = point.color.clone();
|
let mut color = point.color.clone();
|
||||||
|
|
|
@ -308,3 +308,26 @@ impl StreamSource{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Corner{
|
||||||
|
TopLeft,
|
||||||
|
TopRight,
|
||||||
|
BottomRight,
|
||||||
|
BottomLeft,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Corner {
|
||||||
|
pub fn in_laser_space() -> Vec<[f32; 2]>{
|
||||||
|
vec!([-1.,1.], [1.,1.], [1., -1.], [-1.,-1.])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn index(&self) -> usize {
|
||||||
|
match self {
|
||||||
|
Self::TopLeft => 0,
|
||||||
|
Self::TopRight => 1,
|
||||||
|
Self::BottomRight => 2,
|
||||||
|
Self::BottomLeft => 3,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue