add tracing support

This commit is contained in:
Alex Mikhalev 2023-05-08 11:11:23 -07:00
parent a70db904f5
commit 4eccbf78e0
4 changed files with 174 additions and 480 deletions

217
Cargo.lock generated
View File

@ -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"

View File

@ -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"]

View File

@ -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<ResponseRes>,
to_screen: Res<ToScreen>,
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::<Hovered>();
}
});
}
fn update_hover_line(
response: Res<ResponseRes>,
to_screen: Res<ToScreen>,
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::<Hovered>();
}
});
}
fn select_tool(
response: Res<ResponseRes>,
hovered: Query<Entity, With<Hovered>>,
selected: Query<Entity, With<Selected>>,
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::<Selected>();
});
}
// 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::<Selected>();
});
} 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<ResponseRes>,
to_screen: Res<ToScreen>,
mut drag_delta: Local<DragDelta>,
mut point_pos: PointPosQueryMut,
hovered: Query<(Entity, &Point), With<Hovered>>,
selected: Query<(Entity, &Point), With<Selected>>,
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::<Selected>();
});
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<ResponseRes>,
to_screen: Res<ToScreen>,
painter: ResMut<PainterRes>,
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<ResponseRes>,
to_screen: Res<ToScreen>,
painter: ResMut<PainterRes>,
hovered: Query<Entity, (With<Hovered>, With<Point>)>,
selected: Query<(Entity, &geometry::ComputedPointPos), With<Selected>>,
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::<Selected>();
});
}
}
}
fn add_relation_tool(
response: Res<ResponseRes>,
hovered: Query<Entity, With<Hovered>>,
selected: Query<Entity, With<Selected>>,
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::<Selected>();
});
}
}
}
fn is_hovered(response: Res<ResponseRes>) -> bool {
response.hover_pos().is_some()
}
fn is_tool_active(tool: Tool) -> impl System<In = (), Out = bool> + ReadOnlySystem {
IntoSystem::into_system(move |active_tool: Res<Tool>| *active_tool == tool)
}
fn paint_lines(
to_screen: Res<ToScreen>,
painter: ResMut<PainterRes>,
lines: Query<(Entity, &geometry::ComputedLinePos)>,
hovered: Query<(), With<Hovered>>,
selected: Query<(), With<Selected>>,
) {
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<ToScreen>,
painter: ResMut<PainterRes>,
points: Query<(Entity, &geometry::ComputedPointPos)>,
hovered: Query<(), With<Hovered>>,
selected: Query<(), With<Selected>>,
) {
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::<Tool>();
#[cfg(feature = "trace")]
tracing::setup(&mut world);
let mut init_sched = Schedule::new();
init_sched.add_system(init);

50
src/tracing.rs Normal file
View File

@ -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::<FormattedFields<DefaultFields>>()
{
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();
}