From fe17641d46b47f60fc2baa68bb7a0c4e137aa628 Mon Sep 17 00:00:00 2001 From: Artur Sapek Date: Wed, 13 Apr 2022 19:08:53 -0600 Subject: Working multitouch example --- examples/multitouch/src/main.rs | 150 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 examples/multitouch/src/main.rs (limited to 'examples/multitouch/src/main.rs') diff --git a/examples/multitouch/src/main.rs b/examples/multitouch/src/main.rs new file mode 100644 index 00000000..f1d2f216 --- /dev/null +++ b/examples/multitouch/src/main.rs @@ -0,0 +1,150 @@ +//! This example shows how to use touch events in `Canvas` to draw +//! a circle around each fingertip. This only works on touch-enabled +//! computers like Microsoft Surface. +use iced::widget::canvas::event; +use iced::widget::canvas::{self, Canvas, Cursor, Geometry, Path, Stroke}; +use iced::{ + executor, touch, window, Application, Color, Command, Element, Length, + Point, Rectangle, Settings, Subscription, Theme, +}; + +use std::collections::HashMap; + +pub fn main() -> iced::Result { + env_logger::builder().format_timestamp(None).init(); + + Multitouch::run(Settings { + antialiasing: true, + window: window::Settings { + position: window::Position::Centered, + ..window::Settings::default() + }, + ..Settings::default() + }) +} + +struct Multitouch { + state: State, +} + +#[derive(Debug)] +struct State { + cache: canvas::Cache, + fingers: HashMap, +} + +impl State { + fn new() -> Self { + Self { + cache: canvas::Cache::new(), + fingers: HashMap::new(), + } + } +} + +#[derive(Debug)] +enum Message { + FingerPressed { id: touch::Finger, position: Point }, + FingerLifted { id: touch::Finger }, +} + +impl Application for Multitouch { + type Executor = executor::Default; + type Message = Message; + type Theme = Theme; + type Flags = (); + + fn new(_flags: ()) -> (Self, Command) { + ( + Multitouch { + state: State::new(), + }, + Command::none(), + ) + } + + fn title(&self) -> String { + String::from("Multitouch - Iced") + } + + fn update(&mut self, message: Message) -> Command { + match message { + Message::FingerPressed { id, position } => { + self.state.fingers.insert(id, position.clone()); + self.state.cache.clear(); + } + Message::FingerLifted { id } => { + self.state.fingers.remove(&id); + self.state.cache.clear(); + } + } + + Command::none() + } + + fn subscription(&self) -> Subscription { + Subscription::none() + } + + fn view(&self) -> Element { + Canvas::new(&self.state) + .width(Length::Fill) + .height(Length::Fill) + .into() + } +} + +impl<'a> canvas::Program for State { + type State = (); + + fn update( + &self, + _state: &mut Self::State, + event: event::Event, + _bounds: Rectangle, + _cursor: Cursor, + ) -> (event::Status, Option) { + match event { + event::Event::Touch(touch_event) => match touch_event { + touch::Event::FingerPressed { id, position } + | touch::Event::FingerMoved { id, position } => ( + event::Status::Captured, + Some(Message::FingerPressed { id, position }), + ), + touch::Event::FingerLifted { id, .. } + | touch::Event::FingerLost { id, .. } => ( + event::Status::Captured, + Some(Message::FingerLifted { id }), + ), + }, + _ => (event::Status::Ignored, None), + } + } + + fn draw( + &self, + _state: &Self::State, + _theme: &Theme, + bounds: Rectangle, + _cursor: Cursor, + ) -> Vec { + let fingerweb = self.cache.draw(bounds.size(), |frame| { + for finger in &self.fingers { + dbg!(&finger); + + let circle = Path::new(|p| p.circle(*finger.1, 50.0)); + + frame.stroke( + &circle, + Stroke { + color: Color::BLACK, + width: 3.0, + ..Stroke::default() + }, + ); + } + }); + + vec![fingerweb] + } +} -- cgit From 9d6834f250348b00b6bb9dea58ad4c4b58bfab7b Mon Sep 17 00:00:00 2001 From: Artur Sapek Date: Wed, 27 Apr 2022 10:30:32 -0600 Subject: vornoi experiment --- examples/multitouch/src/main.rs | 85 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 80 insertions(+), 5 deletions(-) (limited to 'examples/multitouch/src/main.rs') diff --git a/examples/multitouch/src/main.rs b/examples/multitouch/src/main.rs index f1d2f216..971b1b68 100644 --- a/examples/multitouch/src/main.rs +++ b/examples/multitouch/src/main.rs @@ -9,6 +9,7 @@ use iced::{ }; use std::collections::HashMap; +use voronoi; pub fn main() -> iced::Result { env_logger::builder().format_timestamp(None).init(); @@ -126,16 +127,77 @@ impl<'a> canvas::Program for State { _state: &Self::State, _theme: &Theme, bounds: Rectangle, - _cursor: Cursor, + cursor: Cursor, ) -> Vec { let fingerweb = self.cache.draw(bounds.size(), |frame| { - for finger in &self.fingers { - dbg!(&finger); + let mut fingers = HashMap::new(); + + // TODO delete fake fingers + fingers.insert(1, Point { x: 50.0, y: 50.0 }); + fingers.insert(2, Point { x: 250.0, y: 400.0 }); + fingers.insert(3, Point { x: 650.0, y: 120.0 }); + fingers.insert(4, Point { x: 750.0, y: 520.0 }); + + match cursor { + canvas::Cursor::Available(pt) => { + dbg!(&pt); + fingers.insert(5, pt); + } + _ => {} + } - let circle = Path::new(|p| p.circle(*finger.1, 50.0)); + // Collect tuples of (id, point); + let mut zones: Vec<(i32, Point)> = fingers + .iter() + .map(|(id, pt)| (id.clone(), pt.clone())) + .collect(); + + // Sort by ID + zones.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap()); + + // Generate sorted list of points + let vpoints: Vec = zones + .iter() + .map(|zone| iced_point_to_voronoi_point(&zone.1)) + .collect(); + + let diagram = voronoi::voronoi(vpoints, 700.0); + let polys = voronoi::make_polygons(&diagram); + + for i in 0..polys.len() { + let mut builder = canvas::path::Builder::new(); + let zone = &zones[i]; + let poly = &polys[i]; + + for (index, pt) in poly.iter().enumerate() { + let pt = voronoi_point_to_iced_point(pt); + + match index { + 0 => builder.move_to(pt), + _ => builder.line_to(pt), + } + } + + let path = builder.build(); + + let zone = &zones[i]; + + let color_r = (10 % zone.0) as f32 / 20.0; + let color_g = (10 % (zone.0 + 8)) as f32 / 20.0; + let color_b = (10 % (zone.0 + 3)) as f32 / 20.0; + + frame.fill( + &path, + Color { + r: color_r, + g: color_g, + b: color_b, + a: 1.0, + }, + ); frame.stroke( - &circle, + &path, Stroke { color: Color::BLACK, width: 3.0, @@ -148,3 +210,16 @@ impl<'a> canvas::Program for State { vec![fingerweb] } } + +fn iced_point_to_voronoi_point(pt: &iced::Point) -> voronoi::Point { + voronoi::Point::new(pt.x.into(), pt.y.into()) +} + +fn voronoi_point_to_iced_point(pt: &voronoi::Point) -> iced::Point { + let x: f64 = pt.x.into(); + let y: f64 = pt.y.into(); + Point { + x: x as f32, + y: y as f32, + } +} -- cgit From ddb8f5b96c3d142eb93d6f08367a502a28ed7e39 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 4 Oct 2022 11:35:22 +0200 Subject: Finish `multitouch` example --- examples/multitouch/src/main.rs | 45 +++++++++++++---------------------------- 1 file changed, 14 insertions(+), 31 deletions(-) (limited to 'examples/multitouch/src/main.rs') diff --git a/examples/multitouch/src/main.rs b/examples/multitouch/src/main.rs index 971b1b68..b2bf5427 100644 --- a/examples/multitouch/src/main.rs +++ b/examples/multitouch/src/main.rs @@ -2,14 +2,13 @@ //! a circle around each fingertip. This only works on touch-enabled //! computers like Microsoft Surface. use iced::widget::canvas::event; -use iced::widget::canvas::{self, Canvas, Cursor, Geometry, Path, Stroke}; +use iced::widget::canvas::{self, Canvas, Cursor, Geometry, Stroke}; use iced::{ executor, touch, window, Application, Color, Command, Element, Length, Point, Rectangle, Settings, Subscription, Theme, }; use std::collections::HashMap; -use voronoi; pub fn main() -> iced::Result { env_logger::builder().format_timestamp(None).init(); @@ -127,50 +126,35 @@ impl<'a> canvas::Program for State { _state: &Self::State, _theme: &Theme, bounds: Rectangle, - cursor: Cursor, + _cursor: Cursor, ) -> Vec { let fingerweb = self.cache.draw(bounds.size(), |frame| { - let mut fingers = HashMap::new(); - - // TODO delete fake fingers - fingers.insert(1, Point { x: 50.0, y: 50.0 }); - fingers.insert(2, Point { x: 250.0, y: 400.0 }); - fingers.insert(3, Point { x: 650.0, y: 120.0 }); - fingers.insert(4, Point { x: 750.0, y: 520.0 }); - - match cursor { - canvas::Cursor::Available(pt) => { - dbg!(&pt); - fingers.insert(5, pt); - } - _ => {} + if self.fingers.len() < 2 { + return; } // Collect tuples of (id, point); - let mut zones: Vec<(i32, Point)> = fingers + let mut zones: Vec<(u64, Point)> = self + .fingers .iter() - .map(|(id, pt)| (id.clone(), pt.clone())) + .map(|(id, pt)| (id.0, pt.clone())) .collect(); // Sort by ID zones.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap()); // Generate sorted list of points - let vpoints: Vec = zones - .iter() - .map(|zone| iced_point_to_voronoi_point(&zone.1)) - .collect(); + let vpoints: Vec = + zones.iter().map(|zone| to_voronoi_point(&zone.1)).collect(); let diagram = voronoi::voronoi(vpoints, 700.0); let polys = voronoi::make_polygons(&diagram); - for i in 0..polys.len() { + for (poly, zone) in polys.iter().zip(zones) { let mut builder = canvas::path::Builder::new(); - let zone = &zones[i]; - let poly = &polys[i]; for (index, pt) in poly.iter().enumerate() { - let pt = voronoi_point_to_iced_point(pt); + let pt = from_voronoi_point(pt); match index { 0 => builder.move_to(pt), @@ -180,8 +164,6 @@ impl<'a> canvas::Program for State { let path = builder.build(); - let zone = &zones[i]; - let color_r = (10 % zone.0) as f32 / 20.0; let color_g = (10 % (zone.0 + 8)) as f32 / 20.0; let color_b = (10 % (zone.0 + 3)) as f32 / 20.0; @@ -211,13 +193,14 @@ impl<'a> canvas::Program for State { } } -fn iced_point_to_voronoi_point(pt: &iced::Point) -> voronoi::Point { +fn to_voronoi_point(pt: &iced::Point) -> voronoi::Point { voronoi::Point::new(pt.x.into(), pt.y.into()) } -fn voronoi_point_to_iced_point(pt: &voronoi::Point) -> iced::Point { +fn from_voronoi_point(pt: &voronoi::Point) -> iced::Point { let x: f64 = pt.x.into(); let y: f64 = pt.y.into(); + Point { x: x as f32, y: y as f32, -- cgit From ce2c795bdaca5709fa338f42b9f1c230372bbbbf Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 4 Oct 2022 11:50:32 +0200 Subject: Replace `voronoi` crate with `voronator` --- examples/multitouch/src/main.rs | 40 +++++++++++++++++----------------------- 1 file changed, 17 insertions(+), 23 deletions(-) (limited to 'examples/multitouch/src/main.rs') diff --git a/examples/multitouch/src/main.rs b/examples/multitouch/src/main.rs index b2bf5427..5ac0e58d 100644 --- a/examples/multitouch/src/main.rs +++ b/examples/multitouch/src/main.rs @@ -144,21 +144,29 @@ impl<'a> canvas::Program for State { zones.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap()); // Generate sorted list of points - let vpoints: Vec = - zones.iter().map(|zone| to_voronoi_point(&zone.1)).collect(); + let vpoints: Vec<(f64, f64)> = zones + .iter() + .map(|(_, p)| (f64::from(p.x), f64::from(p.y))) + .collect(); - let diagram = voronoi::voronoi(vpoints, 700.0); - let polys = voronoi::make_polygons(&diagram); + let diagram: voronator::VoronoiDiagram< + voronator::delaunator::Point, + > = voronator::VoronoiDiagram::from_tuple( + &(0.0, 0.0), + &(700.0, 700.0), + &vpoints, + ) + .expect("Generate Voronoi diagram"); - for (poly, zone) in polys.iter().zip(zones) { + for (cell, zone) in diagram.cells().iter().zip(zones) { let mut builder = canvas::path::Builder::new(); - for (index, pt) in poly.iter().enumerate() { - let pt = from_voronoi_point(pt); + for (index, p) in cell.points().iter().enumerate() { + let p = Point::new(p.x as f32, p.y as f32); match index { - 0 => builder.move_to(pt), - _ => builder.line_to(pt), + 0 => builder.move_to(p), + _ => builder.line_to(p), } } @@ -192,17 +200,3 @@ impl<'a> canvas::Program for State { vec![fingerweb] } } - -fn to_voronoi_point(pt: &iced::Point) -> voronoi::Point { - voronoi::Point::new(pt.x.into(), pt.y.into()) -} - -fn from_voronoi_point(pt: &voronoi::Point) -> iced::Point { - let x: f64 = pt.x.into(); - let y: f64 = pt.y.into(); - - Point { - x: x as f32, - y: y as f32, - } -} -- cgit From 8c74464b0d608fb04a1c921b2cbb36b8bc6fc9b8 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 4 Oct 2022 11:53:03 +0200 Subject: Fix `clippy` lints --- examples/multitouch/src/main.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'examples/multitouch/src/main.rs') diff --git a/examples/multitouch/src/main.rs b/examples/multitouch/src/main.rs index 5ac0e58d..0345ceb7 100644 --- a/examples/multitouch/src/main.rs +++ b/examples/multitouch/src/main.rs @@ -70,7 +70,7 @@ impl Application for Multitouch { fn update(&mut self, message: Message) -> Command { match message { Message::FingerPressed { id, position } => { - self.state.fingers.insert(id, position.clone()); + self.state.fingers.insert(id, position); self.state.cache.clear(); } Message::FingerLifted { id } => { @@ -94,7 +94,7 @@ impl Application for Multitouch { } } -impl<'a> canvas::Program for State { +impl canvas::Program for State { type State = (); fn update( @@ -134,11 +134,8 @@ impl<'a> canvas::Program for State { } // Collect tuples of (id, point); - let mut zones: Vec<(u64, Point)> = self - .fingers - .iter() - .map(|(id, pt)| (id.0, pt.clone())) - .collect(); + let mut zones: Vec<(u64, Point)> = + self.fingers.iter().map(|(id, pt)| (id.0, *pt)).collect(); // Sort by ID zones.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap()); -- cgit