Implement clip filter, and fix having no optimizations due to sending a all as single line
This commit is contained in:
parent
ad9c8d6d37
commit
744a3b3dfa
5 changed files with 384 additions and 32 deletions
160
Cargo.lock
generated
160
Cargo.lock
generated
|
@ -2158,6 +2158,16 @@ version = "0.1.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76"
|
checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "earcutr"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "79127ed59a85d7687c409e9978547cffb7dc79675355ed22da6b66fd5f6ead01"
|
||||||
|
dependencies = [
|
||||||
|
"itertools 0.11.0",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ecolor"
|
name = "ecolor"
|
||||||
version = "0.23.0"
|
version = "0.23.0"
|
||||||
|
@ -2597,6 +2607,46 @@ dependencies = [
|
||||||
"typenum",
|
"typenum",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "geo"
|
||||||
|
version = "0.30.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4416397671d8997e9a3e7ad99714f4f00a22e9eaa9b966a5985d2194fc9e02e1"
|
||||||
|
dependencies = [
|
||||||
|
"earcutr",
|
||||||
|
"float_next_after 1.0.0",
|
||||||
|
"geo-types",
|
||||||
|
"geographiclib-rs",
|
||||||
|
"i_overlay",
|
||||||
|
"log",
|
||||||
|
"num-traits",
|
||||||
|
"robust",
|
||||||
|
"rstar",
|
||||||
|
"spade",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "geo-types"
|
||||||
|
version = "0.7.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "62ddb1950450d67efee2bbc5e429c68d052a822de3aad010d28b351fbb705224"
|
||||||
|
dependencies = [
|
||||||
|
"approx 0.5.1",
|
||||||
|
"num-traits",
|
||||||
|
"rayon",
|
||||||
|
"rstar",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "geographiclib-rs"
|
||||||
|
version = "0.2.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f611040a2bb37eaa29a78a128d1e92a378a03e0b6e66ae27398d42b1ba9a7841"
|
||||||
|
dependencies = [
|
||||||
|
"libm",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gethostname"
|
name = "gethostname"
|
||||||
version = "0.4.3"
|
version = "0.4.3"
|
||||||
|
@ -2901,6 +2951,15 @@ dependencies = [
|
||||||
"svg_fmt",
|
"svg_fmt",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hash32"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.12.3"
|
version = "0.12.3"
|
||||||
|
@ -2924,6 +2983,8 @@ version = "0.15.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
|
checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"allocator-api2",
|
||||||
|
"equivalent",
|
||||||
"foldhash",
|
"foldhash",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -2942,6 +3003,16 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "heapless"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad"
|
||||||
|
dependencies = [
|
||||||
|
"hash32",
|
||||||
|
"stable_deref_trait",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heck"
|
name = "heck"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
|
@ -3000,6 +3071,50 @@ dependencies = [
|
||||||
"sample-consensus",
|
"sample-consensus",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "i_float"
|
||||||
|
version = "1.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "85df3a416829bb955fdc2416c7b73680c8dcea8d731f2c7aa23e1042fe1b8343"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "i_key_sort"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "347c253b4748a1a28baf94c9ce133b6b166f08573157e05afe718812bc599fcd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "i_overlay"
|
||||||
|
version = "2.0.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0542dfef184afdd42174a03dcc0625b6147fb73e1b974b1a08a2a42ac35cee49"
|
||||||
|
dependencies = [
|
||||||
|
"i_float",
|
||||||
|
"i_key_sort",
|
||||||
|
"i_shape",
|
||||||
|
"i_tree",
|
||||||
|
"rayon",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "i_shape"
|
||||||
|
version = "1.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0a38f5a42678726718ff924f6d4a0e79b129776aeed298f71de4ceedbd091bce"
|
||||||
|
dependencies = [
|
||||||
|
"i_float",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "i_tree"
|
||||||
|
version = "0.8.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "155181bc97d770181cf9477da51218a19ee92a8e5be642e796661aee2b601139"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iana-time-zone"
|
name = "iana-time-zone"
|
||||||
version = "0.1.63"
|
version = "0.1.63"
|
||||||
|
@ -3149,6 +3264,15 @@ dependencies = [
|
||||||
"either",
|
"either",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itertools"
|
name = "itertools"
|
||||||
version = "0.13.0"
|
version = "0.13.0"
|
||||||
|
@ -5118,6 +5242,12 @@ version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832"
|
checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "robust"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4e27ee8bb91ca0adcf0ecb116293afa12d393f9c2b9b9cd54d33e8078fe19839"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rodio"
|
name = "rodio"
|
||||||
version = "0.19.0"
|
version = "0.19.0"
|
||||||
|
@ -5147,6 +5277,17 @@ version = "0.20.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97"
|
checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rstar"
|
||||||
|
version = "0.12.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "421400d13ccfd26dfa5858199c30a5d76f9c54e0dba7575273025b43c5175dbb"
|
||||||
|
dependencies = [
|
||||||
|
"heapless",
|
||||||
|
"num-traits",
|
||||||
|
"smallvec",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rusb"
|
name = "rusb"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
|
@ -5544,6 +5685,18 @@ dependencies = [
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spade"
|
||||||
|
version = "2.14.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a14e31a007e9f85c32784b04f89e6e194bb252a4d41b4a8ccd9e77245d901c8c"
|
||||||
|
dependencies = [
|
||||||
|
"hashbrown 0.15.3",
|
||||||
|
"num-traits",
|
||||||
|
"robust",
|
||||||
|
"smallvec",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "spirv"
|
name = "spirv"
|
||||||
version = "0.2.0+1.5.4"
|
version = "0.2.0+1.5.4"
|
||||||
|
@ -5563,6 +5716,12 @@ dependencies = [
|
||||||
"bitflags 2.9.1",
|
"bitflags 2.9.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "stable_deref_trait"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "stackfuture"
|
name = "stackfuture"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
|
@ -5984,6 +6143,7 @@ dependencies = [
|
||||||
"bevy",
|
"bevy",
|
||||||
"bevy_nannou",
|
"bevy_nannou",
|
||||||
"cv-core",
|
"cv-core",
|
||||||
|
"geo",
|
||||||
"homography",
|
"homography",
|
||||||
"iyes_perf_ui",
|
"iyes_perf_ui",
|
||||||
"nalgebra 0.30.1",
|
"nalgebra 0.30.1",
|
||||||
|
|
|
@ -23,6 +23,7 @@ serde_repr = "0.1.20"
|
||||||
homography = { git = "https://github.com/azazdeaz/homography" }
|
homography = { git = "https://github.com/azazdeaz/homography" }
|
||||||
nalgebra = "0.30.0"
|
nalgebra = "0.30.0"
|
||||||
cv-core = "0.15.0"
|
cv-core = "0.15.0"
|
||||||
|
geo = "0.30.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ 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, Corner};
|
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::utils::closest_edge;
|
use trap_rust::trap::utils::{closest_edge, split_on_blank};
|
||||||
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;
|
||||||
use std::sync::{mpsc, Arc};
|
use std::sync::{mpsc, Arc};
|
||||||
|
@ -420,7 +420,12 @@ fn laser_frame_producer(model: &mut LaserModel, frame: &mut laser::Frame){
|
||||||
// println!("Cropped Points {} (was: {})", new_laser_points.len(), pointno);
|
// println!("Cropped Points {} (was: {})", new_laser_points.len(), pointno);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
frame.add_lines(new_laser_points);
|
// split by blanked points
|
||||||
|
let lines = split_on_blank(new_laser_points);
|
||||||
|
for line in lines {
|
||||||
|
frame.add_lines(line);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -742,6 +747,21 @@ fn update(_app: &App, model: &mut GuiModel, update: Update) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if ui
|
||||||
|
.checkbox(&mut selected_config.filters.crop.enabled ,"Crop before corrections (recommended)")
|
||||||
|
.changed()
|
||||||
|
{
|
||||||
|
let enabled = selected_config.filters.crop.enabled;
|
||||||
|
if let Some(stream) = selected_laser_stream {
|
||||||
|
stream.send(move |laser_model: &mut LaserModel| {
|
||||||
|
laser_model.config.filters.crop.enabled = enabled;
|
||||||
|
}).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Pincushion / Pillow / Barrel distortion. Generally, only needed for the x-axis
|
// Pincushion / Pillow / Barrel distortion. Generally, only needed for the x-axis
|
||||||
|
|
||||||
if ui
|
if ui
|
||||||
|
@ -794,13 +814,13 @@ fn update(_app: &App, model: &mut GuiModel, update: Update) {
|
||||||
|
|
||||||
|
|
||||||
if ui
|
if ui
|
||||||
.checkbox(&mut selected_config.filters.crop.enabled ,"Crop")
|
.checkbox(&mut selected_config.filters.clip.enabled ,"Apply clip mask")
|
||||||
.changed()
|
.changed()
|
||||||
{
|
{
|
||||||
let enabled = selected_config.filters.crop.enabled;
|
let enabled = selected_config.filters.clip.enabled;
|
||||||
if let Some(stream) = selected_laser_stream {
|
if let Some(stream) = selected_laser_stream {
|
||||||
stream.send(move |laser_model: &mut LaserModel| {
|
stream.send(move |laser_model: &mut LaserModel| {
|
||||||
laser_model.config.filters.crop.enabled = enabled;
|
laser_model.config.filters.clip.enabled = enabled;
|
||||||
}).unwrap();
|
}).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -929,7 +949,7 @@ fn view_laser_preview(app: &App, model: &GuiModel, frame: Frame) {
|
||||||
let draw = app.draw();
|
let draw = app.draw();
|
||||||
|
|
||||||
|
|
||||||
draw.background().color(BLACK);
|
draw.background().color(srgba(0.3,0.3,0.3,1.));
|
||||||
|
|
||||||
let win = app.window_rect();
|
let win = app.window_rect();
|
||||||
|
|
||||||
|
@ -938,7 +958,7 @@ fn view_laser_preview(app: &App, model: &GuiModel, frame: Frame) {
|
||||||
let hh = h / 2.;
|
let hh = h / 2.;
|
||||||
let hw = w / 2.;
|
let hw = w / 2.;
|
||||||
|
|
||||||
let thickness = 2.0;
|
let thickness = 3.0;
|
||||||
|
|
||||||
let win_rect = app.main_window().rect().pad(20.0);
|
let win_rect = app.main_window().rect().pad(20.0);
|
||||||
|
|
||||||
|
@ -979,7 +999,7 @@ fn view_laser_preview(app: &App, model: &GuiModel, frame: Frame) {
|
||||||
}
|
}
|
||||||
|
|
||||||
draw.polygon()
|
draw.polygon()
|
||||||
.color(srgba(1.,1.,1.,3.))
|
.color(srgba(0.3, 0.3, 0.3, 1.))
|
||||||
.stroke(PINK)
|
.stroke(PINK)
|
||||||
.stroke_weight(thickness)
|
.stroke_weight(thickness)
|
||||||
.join_round()
|
.join_round()
|
||||||
|
@ -999,14 +1019,24 @@ fn view_laser_preview(app: &App, model: &GuiModel, frame: Frame) {
|
||||||
let pointno = points.points.len();
|
let pointno = points.points.len();
|
||||||
|
|
||||||
let new_points = config.filters.apply(&points);
|
let new_points = config.filters.apply(&points);
|
||||||
|
let new_laser_points = new_points.points;
|
||||||
|
|
||||||
|
// draw as distinct lines (this is how it is send to post-processing)
|
||||||
|
// TODO: alternatively, if the optimisation becomes an actual filter
|
||||||
|
// this should be drawn as a single line, and we can have an option to
|
||||||
|
// visualise the intermediate lines to make the draw order apparent
|
||||||
|
let lines = split_on_blank(new_laser_points);
|
||||||
|
for line in lines {
|
||||||
// similar to map code:
|
// similar to map code:
|
||||||
|
|
||||||
let vertices = new_points.points.iter().map(|p| {
|
let vertices = line.iter().map(|p| {
|
||||||
let color = srgba(p.color[0], p.color[1], p.color[0], 1.);
|
let color = srgba(p.color[0], p.color[1], p.color[0], 1.);
|
||||||
|
|
||||||
|
|
||||||
let pos = [p.position[0] * hw, p.position[1] * hh];
|
let pos = [p.position[0] * hw, p.position[1] * hh];
|
||||||
|
|
||||||
(pos, color)
|
(pos, color)
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
draw.polyline()
|
draw.polyline()
|
||||||
|
@ -1014,6 +1044,8 @@ fn view_laser_preview(app: &App, model: &GuiModel, frame: Frame) {
|
||||||
.join_round()
|
.join_round()
|
||||||
.points_colored(vertices);
|
.points_colored(vertices);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
draw.to_frame(app, &frame).unwrap();
|
draw.to_frame(app, &frame).unwrap();
|
||||||
|
@ -1124,8 +1156,21 @@ fn laser_mouse_moved(app: &App, model: &mut GuiModel, pos: Point2) {
|
||||||
// config.filters.clip.
|
// config.filters.clip.
|
||||||
let point = config.filters.clip.mask.get_mut(*point_idx).unwrap();
|
let point = config.filters.clip.mask.get_mut(*point_idx).unwrap();
|
||||||
|
|
||||||
|
// set new position
|
||||||
*point = [laser_x, laser_y];
|
*point = [laser_x, laser_y];
|
||||||
|
|
||||||
|
// 3. update config in laser stream threat
|
||||||
|
let mask = config.filters.clip.mask.clone();
|
||||||
|
|
||||||
|
let selected_laser_stream = model.laser_streams.get(&dac_id);
|
||||||
|
if let Some(stream) = selected_laser_stream {
|
||||||
|
stream.send(move |laser_model: &mut LaserModel| {
|
||||||
|
laser_model.config.filters.clip.mask = mask;
|
||||||
|
}).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn laser_mouse_released(_app: &App, model: &mut GuiModel, _button: MouseButton) {
|
fn laser_mouse_released(_app: &App, model: &mut GuiModel, _button: MouseButton) {
|
||||||
|
|
|
@ -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, Corner, LaserPoints}, tracks::CoordinateSpace};
|
use crate::trap::{laser::{apply_homography_matrix, Corner, LaserPoints}, tracks::CoordinateSpace, utils::clip_lines};
|
||||||
|
|
||||||
use nannou_laser::{self as laser, Point};
|
use nannou_laser::{self as laser, Point};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -87,8 +87,9 @@ impl PointFilters {
|
||||||
let mut p = self.dim.apply(points);
|
let mut p = self.dim.apply(points);
|
||||||
p = self.homography.apply(&p);
|
p = self.homography.apply(&p);
|
||||||
p = self.scale.apply(&p);
|
p = self.scale.apply(&p);
|
||||||
p = self.pincushion.apply(&p);
|
|
||||||
p = self.crop.apply(&p);
|
p = self.crop.apply(&p);
|
||||||
|
p = self.pincushion.apply(&p);
|
||||||
|
p = self.clip.apply(&p);
|
||||||
p
|
p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,7 +136,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() },
|
clip: ClipFilter{ enabled: true, mask: Corner::in_laser_space() },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -351,11 +352,9 @@ impl Filter for ClipFilter {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
|
||||||
return LaserPoints{
|
clip_lines(&self.mask, points)
|
||||||
points: points.points.clone(),
|
|
||||||
space: points.space,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reverse(&self, points: &LaserPoints) -> LaserPoints{
|
fn reverse(&self, points: &LaserPoints) -> LaserPoints{
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
// GPT generated code is isolated to this file
|
// GPT generated code is isolated to this file
|
||||||
use geo::{Coordinate, Line, Point, Polygon, prelude::*};
|
use geo::{Coord, Line, Point, Polygon, prelude::*};
|
||||||
|
use geo::line_intersection::{line_intersection, LineIntersection};
|
||||||
|
use nannou_laser::{self as laser};
|
||||||
|
|
||||||
|
use crate::trap::laser::LaserPoints;
|
||||||
|
|
||||||
///////////////////////
|
///////////////////////
|
||||||
// Clip filter related
|
// Clip filter related
|
||||||
|
@ -50,3 +54,146 @@ pub fn closest_edge(mask: &[[f32; 2]], target: [f32; 2]) -> Option<usize> {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
fn interpolate_color(c1: [f32; 3], c2: [f32; 3], t: f32) -> [f32; 3] {
|
||||||
|
[
|
||||||
|
c1[0] + (c2[0] - c1[0]) * t as f32,
|
||||||
|
c1[1] + (c2[1] - c1[1]) * t as f32,
|
||||||
|
c1[2] + (c2[2] - c1[2]) * t as f32,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn interpolate_point(p1: Coord<f32>, p2: Coord<f32>, t: f32) -> Coord<f32> {
|
||||||
|
Coord {
|
||||||
|
x: p1.x + (p2.x - p1.x) * t,
|
||||||
|
y: p1.y + (p2.y - p1.y) * t,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn clip_colored_path(points: &Vec<laser::Point>, bounds: &Polygon<f32>) -> Vec<laser::Point> {
|
||||||
|
let mut result = Vec::new();
|
||||||
|
|
||||||
|
for pair in points.windows(2) {
|
||||||
|
let p1 = &pair[0];
|
||||||
|
let p2 = &pair[1];
|
||||||
|
|
||||||
|
let inside1 = bounds.contains(&Point::from(p1.position));
|
||||||
|
let inside2 = bounds.contains(&Point::from(p2.position));
|
||||||
|
|
||||||
|
let line = Line::new(p1.position, p2.position);
|
||||||
|
|
||||||
|
match (inside1, inside2) {
|
||||||
|
(true, true) => {
|
||||||
|
// Both inside: keep both
|
||||||
|
if result.last().map(|r: &laser::Point| r.position != p1.position).unwrap_or(true) {
|
||||||
|
result.push(p1.clone());
|
||||||
|
}
|
||||||
|
result.push(p2.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
(true, false) | (false, true) => {
|
||||||
|
// Crossing the boundary
|
||||||
|
if let Some(intersection) = line_intersect_polygon(line, bounds) {
|
||||||
|
let t = line_fraction(p1.position, p2.position, intersection);
|
||||||
|
let boundary_color = interpolate_color(p1.color, p2.color, t);
|
||||||
|
|
||||||
|
let boundary_point = laser::Point {
|
||||||
|
position: intersection.into(),
|
||||||
|
color: boundary_color,
|
||||||
|
weight: p1.weight,
|
||||||
|
};
|
||||||
|
|
||||||
|
let blanked_boundary_point = boundary_point.blanked();
|
||||||
|
|
||||||
|
if inside1 {
|
||||||
|
if result.last().map(|r| r.position != p1.position).unwrap_or(true) {
|
||||||
|
result.push(p1.clone());
|
||||||
|
}
|
||||||
|
result.push(boundary_point);
|
||||||
|
result.push(blanked_boundary_point);
|
||||||
|
} else {
|
||||||
|
result.push(blanked_boundary_point);
|
||||||
|
result.push(boundary_point);
|
||||||
|
result.push(p2.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(false, false) => {
|
||||||
|
// Both outside: discard
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
fn line_intersect_polygon(line: Line<f32>, polygon: &Polygon<f32>) -> Option<Coord<f32>> {
|
||||||
|
for edge in polygon.exterior().lines() {
|
||||||
|
|
||||||
|
// if let Some(point) = line.intersection(&edge) {
|
||||||
|
if let Some(point) = line_intersection(line, edge) {
|
||||||
|
return match point {
|
||||||
|
LineIntersection::SinglePoint {intersection, is_proper} => Some(intersection.into()),
|
||||||
|
LineIntersection::Collinear { intersection } => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn line_fraction(start: [f32;2], end: [f32;2], pt: Coord<f32>) -> f32 {
|
||||||
|
let total = ((end[0] - start[0]).powi(2) + (end[1] - start[1]).powi(2)).sqrt();
|
||||||
|
let partial = ((pt.x - start[0]).powi(2) + (pt.y - start[1]).powi(2)).sqrt();
|
||||||
|
if total == 0.0 { 0.0 } else { partial / total }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clip_lines(mask: &Vec<[f32; 2]>, laser_points: &LaserPoints) -> LaserPoints {
|
||||||
|
|
||||||
|
let path = &laser_points.points;
|
||||||
|
|
||||||
|
let bounds = Polygon::new(
|
||||||
|
mask.clone()
|
||||||
|
.into(),
|
||||||
|
vec![],
|
||||||
|
);
|
||||||
|
|
||||||
|
let clipped = clip_colored_path(path, &bounds);
|
||||||
|
|
||||||
|
LaserPoints{
|
||||||
|
points: clipped,
|
||||||
|
space: laser_points.space,
|
||||||
|
}
|
||||||
|
|
||||||
|
// for p in clipped {
|
||||||
|
// println!("Point: {:?}, Color: {:?}", p.position, p.color);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
// split a Vec of laser::Points on blank'ed points, so that the optimiser can do its thing.
|
||||||
|
pub fn split_on_blank(points: Vec<laser::Point>) -> Vec<Vec<laser::Point>> {
|
||||||
|
let mut lines = Vec::new();
|
||||||
|
let mut current_line = Vec::new();
|
||||||
|
|
||||||
|
for point in points {
|
||||||
|
if point.is_blank() {
|
||||||
|
if !current_line.is_empty() {
|
||||||
|
lines.push(current_line);
|
||||||
|
current_line = Vec::new();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
current_line.push(point);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push the last line if not empty
|
||||||
|
if !current_line.is_empty() {
|
||||||
|
lines.push(current_line);
|
||||||
|
}
|
||||||
|
|
||||||
|
lines
|
||||||
|
}
|
Loading…
Reference in a new issue