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"
|
||||
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]]
|
||||
name = "ecolor"
|
||||
version = "0.23.0"
|
||||
|
@ -2597,6 +2607,46 @@ dependencies = [
|
|||
"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]]
|
||||
name = "gethostname"
|
||||
version = "0.4.3"
|
||||
|
@ -2901,6 +2951,15 @@ dependencies = [
|
|||
"svg_fmt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hash32"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.12.3"
|
||||
|
@ -2924,6 +2983,8 @@ version = "0.15.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
|
||||
dependencies = [
|
||||
"allocator-api2",
|
||||
"equivalent",
|
||||
"foldhash",
|
||||
]
|
||||
|
||||
|
@ -2942,6 +3003,16 @@ dependencies = [
|
|||
"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]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
|
@ -3000,6 +3071,50 @@ dependencies = [
|
|||
"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]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.63"
|
||||
|
@ -3149,6 +3264,15 @@ dependencies = [
|
|||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.13.0"
|
||||
|
@ -5118,6 +5242,12 @@ version = "1.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832"
|
||||
|
||||
[[package]]
|
||||
name = "robust"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e27ee8bb91ca0adcf0ecb116293afa12d393f9c2b9b9cd54d33e8078fe19839"
|
||||
|
||||
[[package]]
|
||||
name = "rodio"
|
||||
version = "0.19.0"
|
||||
|
@ -5147,6 +5277,17 @@ version = "0.20.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "rusb"
|
||||
version = "0.7.0"
|
||||
|
@ -5544,6 +5685,18 @@ dependencies = [
|
|||
"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]]
|
||||
name = "spirv"
|
||||
version = "0.2.0+1.5.4"
|
||||
|
@ -5563,6 +5716,12 @@ dependencies = [
|
|||
"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]]
|
||||
name = "stackfuture"
|
||||
version = "0.3.0"
|
||||
|
@ -5984,6 +6143,7 @@ dependencies = [
|
|||
"bevy",
|
||||
"bevy_nannou",
|
||||
"cv-core",
|
||||
"geo",
|
||||
"homography",
|
||||
"iyes_perf_ui",
|
||||
"nalgebra 0.30.1",
|
||||
|
|
|
@ -23,6 +23,7 @@ serde_repr = "0.1.20"
|
|||
homography = { git = "https://github.com/azazdeaz/homography" }
|
||||
nalgebra = "0.30.0"
|
||||
cv-core = "0.15.0"
|
||||
geo = "0.30.0"
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ 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::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 zmq::Socket;
|
||||
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);
|
||||
// }
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -740,6 +745,21 @@ fn update(_app: &App, model: &mut GuiModel, update: Update) {
|
|||
}).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
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
|
||||
|
@ -794,13 +814,13 @@ fn update(_app: &App, model: &mut GuiModel, update: Update) {
|
|||
|
||||
|
||||
if ui
|
||||
.checkbox(&mut selected_config.filters.crop.enabled ,"Crop")
|
||||
.checkbox(&mut selected_config.filters.clip.enabled ,"Apply clip mask")
|
||||
.changed()
|
||||
{
|
||||
let enabled = selected_config.filters.crop.enabled;
|
||||
let enabled = selected_config.filters.clip.enabled;
|
||||
if let Some(stream) = selected_laser_stream {
|
||||
stream.send(move |laser_model: &mut LaserModel| {
|
||||
laser_model.config.filters.crop.enabled = enabled;
|
||||
laser_model.config.filters.clip.enabled = enabled;
|
||||
}).unwrap();
|
||||
}
|
||||
}
|
||||
|
@ -895,9 +915,9 @@ fn view_line_canvas(app: &App, model: &GuiModel, frame: Frame) {
|
|||
});
|
||||
|
||||
draw.polyline()
|
||||
.weight(thickness)
|
||||
.join_round()
|
||||
.points_colored(vertices);
|
||||
.weight(thickness)
|
||||
.join_round()
|
||||
.points_colored(vertices);
|
||||
|
||||
// draggable corners for the selected area
|
||||
if model.selected_stream == Some(dac_id.clone()){
|
||||
|
@ -929,7 +949,7 @@ fn view_laser_preview(app: &App, model: &GuiModel, frame: Frame) {
|
|||
let draw = app.draw();
|
||||
|
||||
|
||||
draw.background().color(BLACK);
|
||||
draw.background().color(srgba(0.3,0.3,0.3,1.));
|
||||
|
||||
let win = app.window_rect();
|
||||
|
||||
|
@ -938,7 +958,7 @@ fn view_laser_preview(app: &App, model: &GuiModel, frame: Frame) {
|
|||
let hh = h / 2.;
|
||||
let hw = w / 2.;
|
||||
|
||||
let thickness = 2.0;
|
||||
let thickness = 3.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()
|
||||
.color(srgba(1.,1.,1.,3.))
|
||||
.color(srgba(0.3, 0.3, 0.3, 1.))
|
||||
.stroke(PINK)
|
||||
.stroke_weight(thickness)
|
||||
.join_round()
|
||||
|
@ -999,20 +1019,32 @@ fn view_laser_preview(app: &App, model: &GuiModel, frame: Frame) {
|
|||
let pointno = points.points.len();
|
||||
|
||||
let new_points = config.filters.apply(&points);
|
||||
let new_laser_points = new_points.points;
|
||||
|
||||
// similar to map code:
|
||||
|
||||
let vertices = new_points.points.iter().map(|p| {
|
||||
let color = srgba(p.color[0], p.color[1], p.color[0], 1.);
|
||||
// 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:
|
||||
|
||||
let pos = [p.position[0] * hw, p.position[1] * hh];
|
||||
(pos, color)
|
||||
});
|
||||
|
||||
draw.polyline()
|
||||
.weight(thickness)
|
||||
.join_round()
|
||||
.points_colored(vertices);
|
||||
let vertices = line.iter().map(|p| {
|
||||
let color = srgba(p.color[0], p.color[1], p.color[0], 1.);
|
||||
|
||||
|
||||
let pos = [p.position[0] * hw, p.position[1] * hh];
|
||||
|
||||
(pos, color)
|
||||
|
||||
});
|
||||
|
||||
draw.polyline()
|
||||
.weight(thickness)
|
||||
.join_round()
|
||||
.points_colored(vertices);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1124,8 +1156,21 @@ fn laser_mouse_moved(app: &App, model: &mut GuiModel, pos: Point2) {
|
|||
// config.filters.clip.
|
||||
let point = config.filters.clip.mask.get_mut(*point_idx).unwrap();
|
||||
|
||||
// set new position
|
||||
*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) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
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 serde::{Deserialize, Serialize};
|
||||
|
@ -87,8 +87,9 @@ impl PointFilters {
|
|||
let mut p = self.dim.apply(points);
|
||||
p = self.homography.apply(&p);
|
||||
p = self.scale.apply(&p);
|
||||
p = self.pincushion.apply(&p);
|
||||
p = self.crop.apply(&p);
|
||||
p = self.pincushion.apply(&p);
|
||||
p = self.clip.apply(&p);
|
||||
p
|
||||
}
|
||||
|
||||
|
@ -135,7 +136,7 @@ impl Default for PointFilters {
|
|||
scale: ScaleFilter { factor: 1. },
|
||||
pincushion: PincushionFilter{k_x: 0.,k_x2: 0., k_y: 0., k_y2: 0.},
|
||||
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{
|
||||
points: points.points.clone(),
|
||||
space: points.space,
|
||||
};
|
||||
|
||||
clip_lines(&self.mask, points)
|
||||
|
||||
}
|
||||
|
||||
fn reverse(&self, points: &LaserPoints) -> LaserPoints{
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
// 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
|
||||
|
@ -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