Points from history into laser points

This commit is contained in:
Ruben van de Ven 2025-04-09 12:40:38 +02:00
parent debd9925d7
commit b170b4fd8e
4 changed files with 146 additions and 72 deletions

View file

@ -8,6 +8,9 @@ use bevy_nannou::NannouPlugin;
use iyes_perf_ui::prelude::*; use iyes_perf_ui::prelude::*;
use nannou_laser::point::Rgb; use nannou_laser::point::Rgb;
use trap::shapes::PositionAndIntensity; use trap::shapes::PositionAndIntensity;
use trap::tracks::LaserPoints;
use trap::tracks::RenderableLines;
use trap::tracks::SpawnedTime;
use trap::tracks::Track; use trap::tracks::Track;
use trap::zmqplugin::ZmqPlugin; use trap::zmqplugin::ZmqPlugin;
// use iyes_perf_ui::PerfUiPlugin; // use iyes_perf_ui::PerfUiPlugin;
@ -31,12 +34,13 @@ fn main() {
.add_systems(Startup, setup) .add_systems(Startup, setup)
.add_systems(Startup, setup_laser) .add_systems(Startup, setup_laser)
.add_systems(Update, update) .add_systems(Update, update)
.add_systems(Update, exit_system)
.add_plugins(ZmqPlugin { .add_plugins(ZmqPlugin {
// url: "tcp://localhost:5558".to_string(), // url: "tcp://localhost:5558".to_string(),
url: "tcp://100.109.175.82:99173".to_string(), // url: "tcp://100.109.175.82:99173".to_string(),
// url: "tcp://127.0.0.1:99173".to_string(), url: "tcp://127.0.0.1:99173".to_string(),
filter: "".to_string() filter: "".to_string()
}) })
@ -47,7 +51,7 @@ fn main() {
#[derive(Resource)] #[derive(Resource)]
struct LaserModel{ struct LaserModel{
t: Instant, // register start time, so that animations can be moving t: Instant, // register start time, so that animations can be moving
current_points: Vec<laser::Point> current_points: LaserPoints
} }
impl LaserModel{ impl LaserModel{
@ -97,7 +101,6 @@ fn setup_laser(mut commands: Commands) {
fn setup(mut commands: Commands) { fn setup(mut commands: Commands) {
// Spawn a camera for our main window // Spawn a camera for our main window
commands.spawn(render::NannouCamera); commands.spawn(render::NannouCamera);
} }
@ -131,6 +134,7 @@ fn laser_frame_producer(model: &mut LaserModel, frame: &mut laser::Frame){
// let points = positions.iter().cloned().map(text2points); // let points = positions.iter().cloned().map(text2points);
let points = model.current_points.clone(); let points = model.current_points.clone();
println!("Points {}", points.len());
frame.add_lines(points); frame.add_lines(points);
} }
@ -153,58 +157,45 @@ struct LaserTimer {
timer: Timer, timer: Timer,
} }
// fn receive_tracks(mut commands: Commands){
// } fn exit_system(keys: Res<ButtonInput<KeyCode>>, mut exit: EventWriter<AppExit>) {
if keys.just_pressed(KeyCode::KeyQ) {
println!("Sending exit command");
exit.send(AppExit::Success);
}
}
fn update( fn update(
mut commands: Commands, // mut commands: Commands,
keys: Res<ButtonInput<KeyCode>>, // keys: Res<ButtonInput<KeyCode>>,
draws: Query<(&Draw, Option<&WindowColor>)>, draws: Query<(&Draw, Option<&WindowColor>)>,
mut lasers: Query<(&mut LaserApi, &mut LaserTimer)>, mut lasers: Query<(&mut LaserApi, &mut LaserTimer)>,
mut count: Local<usize>, tracks: Query<(&Track, &SpawnedTime)>,
time: Res<Time>, time: Res<Time>,
) { ) {
println!("Start update");
if keys.just_pressed(KeyCode::KeyQ) { let mut lines = RenderableLines::new();
// Increment the count to track the number of windows for (track, created_at) in tracks.iter() {
*count += 1; println!("{} {}, history: {}", track.track_id.to_string(), created_at.instant.elapsed().as_millis(), track.history.len());
// We need a render layer to make sure we only render the camera for this window let rl = RenderableLines::from(track);
let layer = RenderLayers::layer(*count); lines.lines.extend(rl.lines);
// Spawn a new window with a unique title, resolution, and background color
let entity = commands
.spawn((
Window {
title: "Nannou".to_string(),
resolution: WindowResolution::new(400.0, 400.0),
..Default::default()
},
layer.clone(),
WindowColor(match *count {
1 => RED.into(),
2 => GREEN.into(),
3 => BLUE.into(),
_ => PURPLE.into(),
}),
))
.id();
// Spawn a camera for our new window with the matching render layer
commands.spawn((render::NannouCamera::for_window(entity), layer.clone()));
} }
for (laser_api, mut laser_timer) in lasers.iter_mut() { for (laser_api, mut laser_timer) in lasers.iter_mut() {
laser_timer.timer.tick(time.delta()); laser_timer.timer.tick(time.delta());
// laser_timer.timer.
let version = laser_timer.timer.elapsed().as_millis() > 500; let version = laser_timer.timer.elapsed().as_millis() > 500;
println!("{} {}", version, laser_timer.timer.elapsed().as_millis()); println!("{} {}", version, laser_timer.timer.elapsed().as_millis());
let lines = get_laser_lines(version); // let lines = get_laser_lines(version);
let points: LaserPoints = (&lines).into();
laser_api.laser_stream.send(|laser| { laser_api.laser_stream.send(|laser| {
laser.current_points = lines; // TODO)) here the render function should run, then in laser_frame_producer, merely take these points and pass along let laserpoints: LaserPoints = points;
// TODO: homography
laser.current_points = laserpoints;
}).unwrap(); }).unwrap();
// println!("Test") println!(" - sent");
} }
for (draw, window_color) in draws.iter() { for (draw, window_color) in draws.iter() {
@ -218,6 +209,6 @@ fn update(
} }
println!("End update");
} }

File diff suppressed because one or more lines are too long

View file

@ -1,5 +1,8 @@
use bevy::prelude::*; use bevy::prelude::*;
use serde::{Serialize,Deserialize}; use serde::{Serialize,Deserialize};
use std::time::Instant;
use nannou_laser as laser;
#[derive(Serialize,Deserialize)] #[derive(Serialize,Deserialize)]
pub struct Frame { pub struct Frame {
@ -36,6 +39,87 @@ pub struct Track {
pub predictions: Option<Vec<Vec<Vec2>>>, pub predictions: Option<Vec<Vec<Vec2>>>,
} }
// coordinates in world space. To be converted to laser::Point or a drawable point
#[derive(Clone)]
pub struct RenderablePoint{
pub position: Vec2,
pub color: Color
}
#[derive(Clone)]
pub struct RenderableLine{
points: Vec<RenderablePoint>
}
#[derive(Clone)]
pub struct RenderableLines{
pub lines: Vec<RenderableLine>
}
impl RenderableLines{
pub fn new() -> Self{
RenderableLines { lines: Vec::new() }
}
// pub fn append(&mut self, &mut rl: RenderableLines){
// self.lines.append(rl.lines);
// }
}
impl From<&RenderablePoint> for laser::Point {
fn from(point: &RenderablePoint) -> Self{
let rgba: Srgba = point.color.into();
let color = [
rgba.red * rgba.alpha,
rgba.green * rgba.alpha,
rgba.blue * rgba.alpha,
];
Self::new(point.position.into(), color)
}
}
impl From<&Track> for RenderableLines{
fn from(track: &Track) -> Self{
let mut lines: Vec<RenderableLine> = Vec::new();
if track.history.len() < 2 {
// no history
} else {
let mut points = Vec::new();
for position in track.history.iter() {
points.push(RenderablePoint{
position: position.clone(),
color: Color::linear_rgba(1.0, 0., 0., 1.0)
});
}
lines.push(RenderableLine{points})
}
RenderableLines { lines }
}
}
pub type LaserPoints = Vec<laser::Point>;
impl From<&RenderableLines> for LaserPoints {
// much like nannou_laser::stream::frame::add_lines()
// turn the lines into a sequence of points with a blanked section inbetween
// this list can then be past as a whole to add_lines()
fn from(lineset: &RenderableLines) -> Self{
let mut points: Vec<laser::Point> = Vec::new();
for line in lineset.lines.iter() {
if points.len() > 0 {
let last = points.last().unwrap();
points.push(last.clone().blanked());
if let Some(first) = line.points.first() {
let laserpoint: nannou_laser::Point = first.into();
points.push(laserpoint.blanked());
points.push(laserpoint);
}
}
points.extend(line.points.iter().map(|p| laser::Point::from(p)));
}
points
}
}
// check: https://www.reddit.com/r/bevy/comments/y1km8n/how_to_link_components_in_bevy_or_am_i_too_oop/ // check: https://www.reddit.com/r/bevy/comments/y1km8n/how_to_link_components_in_bevy_or_am_i_too_oop/
@ -45,25 +129,31 @@ pub struct PredictedTrajectory{
points: Vec<Vec2>, points: Vec<Vec2>,
} }
// #[derive(Bundle)] #[derive(Component)]
// pub struct TrackBundle { pub struct SpawnedTime{
// track: Track, pub instant: Instant,
// // label: TextBundle, }
// }
// impl From<Track> for TrackBundle{ #[derive(Bundle)]
// fn from(track: Track) -> Self { pub struct TrackBundle {
// let name = track.track_id.to_string(); track: Track,
// TrackBundle{ created_at: SpawnedTime,
// track: track, }
// // label: TextBundle{
// // text: Text::from_section(name, TextStyle::default()), impl From<Track> for TrackBundle{
// // transform: Transform::from_translation(250. * Vec3::Y), fn from(track: Track) -> Self {
// // ..default() let name = track.track_id.to_string();
// // } TrackBundle{
// } track: track,
// } created_at: SpawnedTime{instant: Instant::now()}
// } // label: TextBundle{
// text: Text::from_section(name, TextStyle::default()),
// transform: Transform::from_translation(250. * Vec3::Y),
// ..default()
// }
}
}
}
// #[derive(Bundle)] // #[derive(Bundle)]
// pub struct TrackBundle { // pub struct TrackBundle {
@ -82,11 +172,3 @@ pub struct PredictedTrajectory{
pub struct Trajectory { pub struct Trajectory {
pub points: Vec<Vec3>, pub points: Vec<Vec3>,
} }
fn spawn_track() {
}
fn draw_tracks() {
// evyr ææææááá
}

View file

@ -3,7 +3,7 @@ use zmq::Socket;
use serde_json::Result; use serde_json::Result;
use bevy::{ecs::system::SystemState, prelude::*}; use bevy::{ecs::system::SystemState, prelude::*};
use super::tracks::{Frame, Track}; use super::tracks::{Frame, Track, TrackBundle};
// use trap::{Frame, Track, TrackBundle}; // use trap::{Frame, Track, TrackBundle};
@ -30,6 +30,7 @@ fn receive_zmq_messsages(mut commands: Commands, subscriber: NonSend<Socket>, mu
subscriber.as_poll_item(zmq::POLLIN) subscriber.as_poll_item(zmq::POLLIN)
]; ];
let _nr = zmq::poll(&mut items, 0).unwrap(); let _nr = zmq::poll(&mut items, 0).unwrap();
// println!("receive {_nr}");
if items[0].is_readable() { if items[0].is_readable() {
let json = subscriber.recv_string(0).unwrap().unwrap(); let json = subscriber.recv_string(0).unwrap().unwrap();
// dbg!(&json[4..]); // dbg!(&json[4..]);
@ -68,8 +69,8 @@ fn receive_zmq_messsages(mut commands: Commands, subscriber: NonSend<Socket>, mu
// points: Vec::new() // points: Vec::new()
// }; // };
dbg!(&new_track.predictor_history); dbg!(&new_track.predictor_history);
// commands.spawn(TrackBundle::from(new_track)); commands.spawn(TrackBundle::from(new_track));
commands.spawn(new_track); // commands.spawn(new_track);
} }
} }
} }