diff --git a/Cargo.lock b/Cargo.lock index a0d19e0..3de00cc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -165,15 +165,6 @@ version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" -[[package]] -name = "approx" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f2a05fd1bd10b2527e20a2cd32d8873d115b8b39fe219ee25f42a8aca6ba278" -dependencies = [ - "num-traits", -] - [[package]] name = "approx" version = "0.5.1" @@ -233,8 +224,6 @@ dependencies = [ "anyhow", "cfg-if", "nalgebra", - "ndarray", - "ndarray-linalg", "num-complex", "num-integer", "num-traits", @@ -678,27 +667,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" -[[package]] -name = "cauchy" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ff11ddd2af3b5e80dd0297fee6e56ac038d9bdc549573cdb51bd6d2efe7f05e" -dependencies = [ - "num-complex", - "num-traits", - "rand", - "serde", -] - -[[package]] -name = "cblas-sys" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6feecd82cce51b0204cf063f0041d69f24ce83f680d87514b004248e7b0fa65" -dependencies = [ - "libc", -] - [[package]] name = "cc" version = "1.0.79" @@ -1597,45 +1565,12 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "katexit" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb1304c448ce2c207c2298a34bc476ce7ae47f63c23fa2b498583b26be9bc88c" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "khronos_api" version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" -[[package]] -name = "lapack-sys" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "447f56c85fb410a7a3d36701b2153c1018b1d2b908c5fbaf01c1b04fac33bcbe" -dependencies = [ - "libc", -] - -[[package]] -name = "lax" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f96a229d9557112e574164f8024ce703625ad9f88a90964c1780809358e53da" -dependencies = [ - "cauchy", - "katexit", - "lapack-sys", - "num-traits", - "thiserror", -] - [[package]] name = "lazy_static" version = "1.4.0" @@ -1710,6 +1645,15 @@ dependencies = [ "libc", ] +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata", +] + [[package]] name = "matrixmultiply" version = "0.3.7" @@ -1796,7 +1740,7 @@ version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d68d47bba83f9e2006d117a9a33af1524e655516b8919caac694427a6fb1e511" dependencies = [ - "approx 0.5.1", + "approx", "matrixmultiply", "nalgebra-macros", "num-complex", @@ -1804,7 +1748,6 @@ dependencies = [ "num-traits", "rand", "rand_distr", - "serde", "simba", "typenum", ] @@ -1830,39 +1773,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "ndarray" -version = "0.15.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb12d4e967ec485a5f71c6311fe28158e9d6f4bc4a447b474184d0f91a8fa32" -dependencies = [ - "approx 0.4.0", - "cblas-sys", - "libc", - "matrixmultiply", - "num-complex", - "num-integer", - "num-traits", - "rawpointer", - "serde", -] - -[[package]] -name = "ndarray-linalg" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b0e8dda0c941b64a85c5deb2b3e0144aca87aced64678adfc23eacea6d2cc42" -dependencies = [ - "cauchy", - "katexit", - "lax", - "ndarray", - "num-complex", - "num-traits", - "rand", - "thiserror", -] - [[package]] name = "ndk" version = "0.7.0" @@ -1946,6 +1856,16 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num-complex" version = "0.4.3" @@ -1953,8 +1873,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d" dependencies = [ "num-traits", - "rand", - "serde", ] [[package]] @@ -2120,6 +2038,12 @@ version = "6.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267" +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "owned_ttf_parser" version = "0.19.0" @@ -2412,9 +2336,24 @@ checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370" dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-syntax 0.7.1", ] +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + [[package]] name = "regex-syntax" version = "0.7.1" @@ -2576,13 +2515,22 @@ dependencies = [ "digest", ] +[[package]] +name = "sharded-slab" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +dependencies = [ + "lazy_static", +] + [[package]] name = "simba" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "061507c94fc6ab4ba1c9a0305018408e312e17c041eb63bef8aa726fa33aceae" dependencies = [ - "approx 0.5.1", + "approx", "num-complex", "num-traits", "paste", @@ -2611,6 +2559,10 @@ dependencies = [ "nohash-hasher", "rand", "rand_distr", + "tracing", + "tracing-chrome", + "tracing-error", + "tracing-subscriber", ] [[package]] @@ -2944,6 +2896,17 @@ dependencies = [ "syn 2.0.15", ] +[[package]] +name = "tracing-chrome" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "496b3cd5447f7ff527bbbf19b071ad542a000adf297d4127078b4dfdb931f41a" +dependencies = [ + "serde_json", + "tracing-core", + "tracing-subscriber", +] + [[package]] name = "tracing-core" version = "0.1.30" @@ -2951,6 +2914,46 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-error" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" +dependencies = [ + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "tracing-log" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +dependencies = [ + "lazy_static", + "log", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", ] [[package]] @@ -3017,6 +3020,12 @@ dependencies = [ "serde", ] +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "vec_map" version = "0.8.2" diff --git a/Cargo.toml b/Cargo.toml index 63cbd48..6f0e440 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] argmin = { version = "0.8.1", features = [] } -argmin-math = { version = "0.3.0", features = ["latest_all"] } +argmin-math = { version = "0.3.0", features = ["nalgebra_v0_32"] } bevy_ecs = "0.10.1" eframe = { version = "0.21.3" } indexmap = "1.8.1" @@ -17,7 +17,13 @@ nalgebra-sparse = "0.9.0" nohash-hasher = "0.2.0" rand = "0.8.5" rand_distr = "0.4.3" +tracing = { version = "0.1.37", optional = true } +tracing-chrome = { version = "0.7.1", optional = true } +tracing-error = { version = "0.2.0", optional = true } +tracing-subscriber = { version = "0.3.17", features = ["env-filter"], optional = true } [dev-dependencies] criterion = "0.4.0" +[features] +trace = ["tracing", "tracing-subscriber", "tracing-chrome", "tracing-error", "bevy_ecs/trace"] diff --git a/src/main.rs b/src/main.rs index 4bbad3b..46c9914 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,380 +15,8 @@ use geometry::{Line, LineBundle, Point, PointId, PointPos, PointPosQueryMut}; mod geometry; pub mod optimization; mod relations; - -#[derive(Clone, Copy, PartialEq, Resource)] -enum Tool { - Select, - Move, - AddPoint, - AddLine, - AddRelation, -} - -#[allow(clippy::derivable_impls)] -impl Default for Tool { - fn default() -> Self { - Tool::Select - } -} - -#[derive(Resource)] -struct ResponseRes(Response); - -impl Deref for ResponseRes { - type Target = Response; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Resource)] -struct PainterRes(Painter); - -impl Deref for PainterRes { - type Target = Painter; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} -impl DerefMut for PainterRes { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - -#[derive(Resource)] -struct ToScreen(RectTransform); - -impl ToScreen { - fn transform_pos(&self, pos: &PointPos) -> Pos2 { - self.0 * Pos2::new(pos.x as f32, pos.y as f32) - } - - fn inverse_transform(&self, pos: Pos2) -> Pos2 { - self.0.inverse() * pos - } - - fn inverse_transform_to_point(&self, pos: Pos2) -> PointPos { - let pos = self.inverse_transform(pos); - PointPos::new(pos.x as f64, pos.y as f64) - } -} - -#[derive(Component)] -struct Hovered; - -#[derive(Component)] -struct Selected; - -fn color_for_var_status(status: geometry::VarStatus) -> Hsva { - use geometry::VarStatus::*; - match status { - Free => Hsva::new(200. / 360., 0.90, 0.80, 1.0), - Dependent => todo!(), - Unique => todo!(), - Overconstrained => todo!(), - } -} - -const POINT_RADIUS: f32 = 3.0; - -fn update_hover_point( - response: Res, - to_screen: Res, - points: Query<(PointId, &geometry::ComputedPointPos)>, - mut commands: Commands, -) { - points.for_each(|(id, pos)| { - let hovered = if let Some(hover_pos) = response.hover_pos() { - let center = to_screen.transform_pos(pos); - - (hover_pos - center).length() < (POINT_RADIUS * 3.) - } else { - false - }; - - if hovered { - commands.entity(id).insert(Hovered); - } else { - commands.entity(id).remove::(); - } - }); -} - -fn update_hover_line( - response: Res, - to_screen: Res, - lines: Query<(Entity, &geometry::ComputedLinePos)>, - mut commands: Commands, -) { - lines.for_each(|(id, pos)| { - let hovered = if let Some(hover_pos) = response.hover_pos() { - let points = [ - to_screen.transform_pos(&pos.start), - to_screen.transform_pos(&pos.end), - ]; - - let b = points[1] - points[0]; - let a = hover_pos - points[0]; - let p = a.dot(b) / b.dot(b); - let perp = a - (p * b); - ((0.)..=1.).contains(&p) && perp.length() < 5.0 - } else { - false - }; - - if hovered { - commands.entity(id).insert(Hovered); - } else { - commands.entity(id).remove::(); - } - }); -} - -fn select_tool( - response: Res, - hovered: Query>, - selected: Query>, - mut commands: Commands, -) { - response.ctx.output_mut(|output| { - output.cursor_icon = if !hovered.is_empty() { - CursorIcon::PointingHand - } else { - CursorIcon::Default - } - }); - - if response.clicked() { - if !response.ctx.input(|input| input.modifiers.shift) { - selected.for_each(|selected| { - commands.entity(selected).remove::(); - }); - } - // TODO: choose which to select - if let Some(hovered) = hovered.iter().next() { - commands.entity(hovered).insert(Selected); - } - } - - if response - .ctx - .input(|input| input.key_pressed(egui::Key::Escape)) - { - selected.for_each(|selected| { - commands.entity(selected).remove::(); - }); - } else if response - .ctx - .input(|input| input.key_pressed(egui::Key::Delete)) - { - selected.for_each(|selected| { - commands.entity(selected).despawn(); - }); - } -} - -#[derive(Default)] -struct DragDelta(Vec2); - -// TODO: move other entities -fn move_tool( - response: Res, - to_screen: Res, - mut drag_delta: Local, - mut point_pos: PointPosQueryMut, - hovered: Query<(Entity, &Point), With>, - selected: Query<(Entity, &Point), With>, - mut commands: Commands, -) { - let hover_pos = response.hover_pos().unwrap(); - - response.ctx.output_mut(|o| { - o.cursor_icon = if !selected.is_empty() { - CursorIcon::Grabbing - } else if !hovered.is_empty() { - CursorIcon::Grab - } else { - CursorIcon::Move - } - }); - - let selected = if response.drag_started() { - // TODO: choose which to select - let to_select = hovered.iter().next(); - if let Some(hovered) = to_select { - commands.entity(hovered.0).insert(Selected); - } - to_select - } else if response.drag_released() { - selected.for_each(|selected| { - commands.entity(selected.0).remove::(); - }); - drag_delta.0 = Vec2::ZERO; - None - } else { - selected.iter().next() - }; - - if let Some((_, point)) = selected { - if response.drag_started() { - let drag_point_pos = point_pos.get(point).unwrap(); - drag_delta.0 = hover_pos - to_screen.transform_pos(&drag_point_pos); - } - let move_to = to_screen.inverse_transform_to_point(hover_pos - drag_delta.0); - point_pos.set(point, move_to).unwrap(); - } -} - -fn add_point(commands: &mut Commands, pos: Pos2, to_screen: &ToScreen) -> PointId { - let point_pos = to_screen.inverse_transform(pos); - let point_pos = (point_pos.x as f64, point_pos.y as f64); - geometry::insert_point_at(commands, point_pos) -} - -fn add_point_tool( - response: Res, - to_screen: Res, - painter: ResMut, - mut commands: Commands, -) { - let hover_pos = response.hover_pos().unwrap(); - if response.clicked() { - add_point(&mut commands, hover_pos, &to_screen); - } else { - painter.circle_filled(hover_pos, POINT_RADIUS, Color32::WHITE); - } -} - -fn add_line_tool( - response: Res, - to_screen: Res, - painter: ResMut, - hovered: Query, With)>, - selected: Query<(Entity, &geometry::ComputedPointPos), With>, - mut commands: Commands, -) { - let hover_pos = response.hover_pos().unwrap(); - - match (selected.iter().next(), response.clicked()) { - (None, false) => { - painter.circle_filled(hover_pos, POINT_RADIUS, Color32::DARK_GRAY); - } - (None, true) => { - let point_id = match hovered.iter().next() { - Some(hovered) => hovered, - None => add_point(&mut commands, hover_pos, &to_screen), - }; - commands.entity(point_id).insert(Selected); - } - (Some((_, start_point_pos)), false) => { - let points = [to_screen.transform_pos(start_point_pos), hover_pos]; - - let stroke = Stroke::new(2.0, Color32::DARK_GRAY); - - painter.line_segment(points, stroke); - - painter.circle_filled(hover_pos, POINT_RADIUS, Color32::DARK_GRAY); - } - (Some((start_point_id, _)), true) => { - // TODO: add point if no hover point - let end_point = hovered - .iter() - .next() - .unwrap_or_else(|| add_point(&mut commands, hover_pos, &to_screen)); - - let line = LineBundle::new(start_point_id, end_point); - commands.spawn(line); - - selected.for_each(|(selected_id, _)| { - commands.entity(selected_id).remove::(); - }); - } - } -} - -fn add_relation_tool( - response: Res, - hovered: Query>, - selected: Query>, - mut commands: Commands, -) { - response.ctx.output_mut(|o| { - o.cursor_icon = if !hovered.is_empty() { - CursorIcon::PointingHand - } else { - CursorIcon::Default - } - }); - - if response.clicked() { - // TODO: choose which to select - if let Some(hovered) = hovered.iter().next() { - commands.entity(hovered).insert(Selected); - } else { - selected.for_each(|selected| { - commands.entity(selected).remove::(); - }); - } - } -} - -fn is_hovered(response: Res) -> bool { - response.hover_pos().is_some() -} - -fn is_tool_active(tool: Tool) -> impl System + ReadOnlySystem { - IntoSystem::into_system(move |active_tool: Res| *active_tool == tool) -} - -fn paint_lines( - to_screen: Res, - painter: ResMut, - lines: Query<(Entity, &geometry::ComputedLinePos)>, - hovered: Query<(), With>, - selected: Query<(), With>, -) { - lines.for_each(|(id, pos)| { - let points = [ - to_screen.transform_pos(&pos.start), - to_screen.transform_pos(&pos.end), - ]; - - let mut color = color_for_var_status(pos.status); - color.v -= 0.6; - if hovered.contains(id) || selected.contains(id) { - color.s -= 0.8; - } - - let stroke = Stroke::new(2.0, color); - - painter.line_segment(points, stroke); - }); -} - -fn paint_points( - to_screen: Res, - painter: ResMut, - points: Query<(Entity, &geometry::ComputedPointPos)>, - hovered: Query<(), With>, - selected: Query<(), With>, -) { - points.for_each(|(id, pos)| { - let center = to_screen.transform_pos(pos); - - let color = color_for_var_status(pos.status); - let stroke = if selected.contains(id) || hovered.contains(id) { - // color.s -= 0.8; - Stroke::new(1.0, Color32::WHITE) - } else { - Stroke::default() - }; - painter.circle(center, POINT_RADIUS, color, stroke); - }); -} +#[cfg(feature = "trace")] +mod tracing; fn init(mut commands: Commands) { let p1 = geometry::insert_point_at(&mut commands, (10., 30.)); @@ -607,7 +235,8 @@ impl MyApp { fn new() -> Self { let mut world = World::default(); - world.init_resource::(); + #[cfg(feature = "trace")] + tracing::setup(&mut world); let mut init_sched = Schedule::new(); init_sched.add_system(init); diff --git a/src/tracing.rs b/src/tracing.rs new file mode 100644 index 0000000..c5ebfb1 --- /dev/null +++ b/src/tracing.rs @@ -0,0 +1,50 @@ +use std::panic; + +use bevy_ecs::world::World; +use tracing::Level; +use tracing_subscriber::{ + fmt::{format::DefaultFields, FormattedFields}, + prelude::*, + EnvFilter, Registry, +}; + +pub fn setup(world: &mut World) { + let old_handler = panic::take_hook(); + panic::set_hook(Box::new(move |infos| { + println!("{}", tracing_error::SpanTrace::capture()); + old_handler(infos); + })); + + let default_filter = { format!("{},{}", Level::INFO, "") }; + let filter_layer = EnvFilter::try_from_default_env() + .or_else(|_| EnvFilter::try_new(&default_filter)) + .unwrap(); + let subscriber = Registry::default().with(filter_layer); + + let subscriber = subscriber.with(tracing_error::ErrorLayer::default()); + + let chrome_layer = { + let mut layer = tracing_chrome::ChromeLayerBuilder::new(); + if let Ok(path) = std::env::var("TRACE_CHROME") { + layer = layer.file(path); + } + let (chrome_layer, guard) = layer + .name_fn(Box::new(|event_or_span| match event_or_span { + tracing_chrome::EventOrSpan::Event(event) => event.metadata().name().into(), + tracing_chrome::EventOrSpan::Span(span) => { + if let Some(fields) = span.extensions().get::>() + { + format!("{}: {}", span.metadata().name(), fields.fields.as_str()) + } else { + span.metadata().name().into() + } + } + })) + .build(); + world.insert_non_send_resource(guard); + chrome_layer + }; + let subscriber = subscriber.with(chrome_layer); + + tracing::subscriber::set_global_default(subscriber).unwrap(); +}