diff --git a/rmf_site_editor/Cargo.toml b/rmf_site_editor/Cargo.toml index 5737d7da..cc7f4ce2 100644 --- a/rmf_site_editor/Cargo.toml +++ b/rmf_site_editor/Cargo.toml @@ -21,7 +21,6 @@ bevy_polyline = "0.4" bevy_stl = "0.7.0" bevy_obj = { git = "https://github.com/luca-della-vedova/bevy_obj", branch = "luca/scene_0.9", features = ["scene"]} bevy_rapier3d = "0.20.0" -crossbeam-channel = "0.5.0" smallvec = "*" serde = { version = "1.0", features = ["derive"] } serde_yaml = "0.8.23" @@ -31,6 +30,7 @@ wasm-bindgen = "=0.2.84" web-sys = { version = "0.3.56", features = ["console"] } futures-lite = "1.12.0" bevy = "0.9" +bevy_utils = "0.9" dirs = "4.0" thread_local = "*" lyon = "1" @@ -38,6 +38,9 @@ thiserror = "*" rmf_site_format = { path = "../rmf_site_format", features = ["bevy"] } itertools = "*" bitfield = "*" +crossbeam-channel = "0.5" +tracing = "0.1.37" +tracing-subscriber = "0.3.1" rfd = "0.11" urdf-rs = "0.7" # sdformat_rs = { path = "../../sdf_rust_experimental/sdformat_rs"} diff --git a/rmf_site_editor/src/interaction/cursor.rs b/rmf_site_editor/src/interaction/cursor.rs index f661d2e5..d57ed2ee 100644 --- a/rmf_site_editor/src/interaction/cursor.rs +++ b/rmf_site_editor/src/interaction/cursor.rs @@ -354,7 +354,7 @@ pub fn update_cursor_transform( let mut transform = match transforms.get_mut(cursor.frame) { Ok(transform) => transform, Err(_) => { - println!("No cursor transform found"); + error!("No cursor transform found"); return; } }; diff --git a/rmf_site_editor/src/interaction/light.rs b/rmf_site_editor/src/interaction/light.rs index 127f4832..1c04e6d6 100644 --- a/rmf_site_editor/src/interaction/light.rs +++ b/rmf_site_editor/src/interaction/light.rs @@ -171,7 +171,7 @@ pub fn update_physical_light_visual_cues( if let Some(m) = material_assets.get_mut(material) { m.base_color = kind.color().into(); } else { - println!("DEV ERROR: Unable to get material asset for light"); + error!("Unable to get material asset for light"); } if kind.is_directional() { diff --git a/rmf_site_editor/src/interaction/select_anchor.rs b/rmf_site_editor/src/interaction/select_anchor.rs index 67ceb38e..f104e919 100644 --- a/rmf_site_editor/src/interaction/select_anchor.rs +++ b/rmf_site_editor/src/interaction/select_anchor.rs @@ -164,8 +164,8 @@ impl TargetTransition { match e { Some(e) => { if self.created.is_some() { - println!( - "DEV ERROR: Created a superfluous target while in \ + error!( + "Created a superfluous target while in \ SelectAnchor mode" ); } @@ -174,8 +174,8 @@ impl TargetTransition { None => match self.created { Some(e) => Some(e), None => { - println!( - "DEV ERROR: Failed to create an entity while in \ + error!( + "Failed to create an entity while in \ SelectAnchor mode" ); None @@ -276,7 +276,7 @@ impl AnchorSelection { Ok(dep) => dep, Err(_) => { // The entity was not a proper anchor - println!("DEV ERROR: Invalid anchor selected {:?}", e); + error!("Invalid anchor selected {:?}", e); return Err(()); } }; @@ -301,7 +301,7 @@ impl AnchorSelection { let mut deps = match params.dependents.get_mut(*e).map_err(|_| ()) { Ok(dep) => dep, Err(_) => { - println!("DEV ERROR: Invalid anchor selected {:?}", e); + error!("Invalid anchor selected {:?}", e); return Err(()); } }; @@ -394,8 +394,8 @@ impl EdgePlacement { // Do nothing } Err(_) => { - println!( - "DEV ERROR: No AnchorDependents component found for \ + error!( + "No AnchorDependents component found for \ {:?} while in SelectAnchor mode.", old_anchor ); @@ -435,8 +435,8 @@ impl Placement for EdgePlacement { match params.edges.get_mut(target) { Ok((edge, original)) => (target, edge, original), Err(_) => { - println!( - "DEV ERROR: Entity {:?} is not the right kind of \ + error!( + "Entity {:?} is not the right kind of \ element", target, ); @@ -592,15 +592,15 @@ impl Placement for EdgePlacement { Self::update_dependencies(None, target, old_edge, *edge, params)?; return Ok((TargetTransition::finished(), self.to_start()).into()); } else { - println!( - "DEV ERROR: Unable to find original for {target:?} \ + error!( + "Unable to find original for {target:?} \ while backing out of edge replacement" ); return Err(()); } } else { - println!( - "DEV ERROR: Unable to find edge for {target:?} while \ + error!( + "Unable to find edge for {target:?} while \ backing out of edge replacement" ); return Err(()); @@ -678,8 +678,8 @@ impl Placement for PointPlacement { let mut point = match params.points.get_mut(target) { Ok(l) => l, Err(_) => { - println!( - "DEV ERROR: Unable to get location {:?} while in \ + error!( + "Unable to get location {:?} while in \ SelectAnchor mode.", target ); @@ -764,8 +764,8 @@ impl Placement for PointPlacement { return Ok((TargetTransition::discontinued(), self.transition()).into()); } } else { - println!( - "DEV ERROR: Cannot find point for location {target:?} while \ + error!( + "Cannot find point for location {target:?} while \ trying to back out of SelectAnchor mode" ); return Err(()); @@ -862,8 +862,8 @@ impl Placement for PathPlacement { let (mut path, behavior) = match params.paths.get_mut(target) { Ok(q) => q, Err(_) => { - println!( - "DEV ERROR: Unable to find path info for {target:?} while \ + error!( + "Unable to find path info for {target:?} while \ in SelectAnchor mode." ); return Err(()); @@ -932,8 +932,8 @@ impl Placement for PathPlacement { let path = match params.paths.get(target) { Ok(p) => p.0, Err(_) => { - println!( - "DEV ERROR: Unable to find path for {:?} while in \ + error!( + "Unable to find path for {:?} while in \ SelectAnchor mode", target, ); @@ -952,8 +952,8 @@ impl Placement for PathPlacement { let path = match params.paths.get(target) { Ok(p) => p.0.clone(), Err(_) => { - println!( - "DEV ERROR: Unable to find path for {:?} while in \ + error!( + "Unable to find path for {:?} while in \ SelectAnchor mode", target, ); @@ -988,8 +988,8 @@ impl Placement for PathPlacement { return Ok((TargetTransition::finished(), self.restart()).into()); } - println!( - "DEV ERROR: Path of length {} is missing the index {} \ + error!( + "Path of length {} is missing the index {} \ that was supposed to be replaced.", path.len(), index @@ -997,8 +997,8 @@ impl Placement for PathPlacement { return Err(()); } - println!( - "DEV ERROR: Unable to find the placement of a path anchor \ + error!( + "Unable to find the placement of a path anchor \ that is being replaced." ); return Err(()); @@ -1081,8 +1081,8 @@ impl<'w, 's> SelectAnchorPlacementParams<'w, 's> { let mut deps = match self.dependents.get_mut(to_anchor).map_err(|_| ()) { Ok(dep) => dep, Err(_) => { - println!( - "DEV ERROR: Trying to insert invalid anchor \ + error!( + "Trying to insert invalid anchor \ {to_anchor:?} into entity {dependent:?}" ); return Err(()); @@ -1107,8 +1107,8 @@ impl<'w, 's> SelectAnchorPlacementParams<'w, 's> { let mut deps = match self.dependents.get_mut(from_anchor).map_err(|_| ()) { Ok(dep) => dep, Err(_) => { - println!( - "DEV ERROR: Removing invalid anchor {from_anchor:?} \ + error!( + "Removing invalid anchor {from_anchor:?} \ from entity {dependent:?}" ); return Err(()); @@ -1432,8 +1432,8 @@ impl SelectAnchor { params.commands.entity(finished_target).remove::(); self.placement.finalize(finished_target, params); } else { - println!( - "DEV ERROR: An element was supposed to be finished by \ + error!( + "An element was supposed to be finished by \ SelectAnchor, but we could not find it" ); } @@ -1665,8 +1665,8 @@ impl SelectAnchor3D { let (e, anchor) = match params.anchors.get_mut(target) { Ok(l) => l, Err(_) => { - println!( - "DEV ERROR: Unable to get anchor {:?} while \ + error!( + "Unable to get anchor {:?} while \ replacing 3D Anchor.", target ); @@ -1722,14 +1722,14 @@ impl SelectAnchor3D { return Ok(()); } None => { - println!("DEV ERROR: Reassigning parent for entity without a parent"); + error!("Reassigning parent for entity without a parent"); return Err(()); } } } return Err(()); } else { - println!("DEV error replacing anchor without original"); + error!("DEV error replacing anchor without original"); return Err(()); } } @@ -1790,8 +1790,8 @@ impl SelectAnchor3D { return Err(()); } } else { - println!( - "DEV ERROR: Cannot find point for location {target:?} while \ + error!( + "Cannot find point for location {target:?} while \ trying to back out of SelectAnchor mode" ); return Err(()); @@ -1902,8 +1902,8 @@ pub fn handle_select_anchor_mode( let for_element = match request.target { Some(for_element) => for_element, None => { - println!( - "DEV ERROR: for_element must be Some for ReplaceAnchor. \ + error!( + "for_element must be Some for ReplaceAnchor. \ Reverting to Inspect Mode." ); params.cleanup(); @@ -1915,8 +1915,8 @@ pub fn handle_select_anchor_mode( let original = match request.placement.save_original(for_element, &mut params) { Some(original) => original, None => { - println!( - "DEV ERROR: cannot locate an original anchor for \ + error!( + "cannot locate an original anchor for \ entity {:?}. Reverting to Inspect Mode.", for_element, ); @@ -1960,8 +1960,8 @@ pub fn handle_select_anchor_mode( let tf = match transforms.get(params.cursor.frame) { Ok(tf) => tf, Err(_) => { - println!( - "DEV ERROR: Could not get transform for cursor frame \ + error!( + "Could not get transform for cursor frame \ {:?} in SelectAnchor mode.", params.cursor.frame, ); @@ -2191,7 +2191,6 @@ pub fn handle_select_anchor_3d_mode( parent } PlaceableObject::Model(ref a) => { - println!("Creating model for entity {:?}", id); let mut model = a.clone(); let parent = workspace.root.expect("No workspace"); model.pose = compute_parent_inverse_pose(&cursor_tf, &transforms, parent); @@ -2199,7 +2198,6 @@ pub fn handle_select_anchor_3d_mode( parent } PlaceableObject::WorkcellVisual(ref a) => { - println!("Creating visual for entity {:?}", id); let mut model = a.clone(); let parent = request .parent @@ -2211,7 +2209,6 @@ pub fn handle_select_anchor_3d_mode( parent } PlaceableObject::WorkcellCollision(ref a) => { - println!("Creating collision for entity {:?}", id); let mut model = a.clone(); let parent = request .parent diff --git a/rmf_site_editor/src/keyboard.rs b/rmf_site_editor/src/keyboard.rs index efded4c7..a69b703a 100644 --- a/rmf_site_editor/src/keyboard.rs +++ b/rmf_site_editor/src/keyboard.rs @@ -86,14 +86,14 @@ fn handle_keyboard_input( if let Some(selection) = selection.0 { delete.send(Delete::new(selection)); } else { - println!("No selected entity to delete"); + warn!("No selected entity to delete"); } } } if keyboard_input.just_pressed(KeyCode::D) { debug_mode.0 = !debug_mode.0; - println!("Toggling debug mode: {debug_mode:?}"); + info!("Toggling debug mode: {debug_mode:?}"); } // Ctrl keybindings diff --git a/rmf_site_editor/src/lib.rs b/rmf_site_editor/src/lib.rs index eeeacfc4..733ee98e 100644 --- a/rmf_site_editor/src/lib.rs +++ b/rmf_site_editor/src/lib.rs @@ -31,8 +31,10 @@ pub mod occupancy; use occupancy::OccupancyPlugin; mod demo_world; +mod log; mod recency; mod shapes; +use log::LogHistoryPlugin; mod main_menu; use main_menu::Autoload; @@ -125,6 +127,8 @@ pub fn run(command_line_args: Vec) { { app.add_plugins( DefaultPlugins + .build() + .disable::() .set(WindowPlugin { window: WindowDescriptor { title: "RMF Site Editor".to_owned(), @@ -146,6 +150,8 @@ pub fn run(command_line_args: Vec) { { app.add_plugins( DefaultPlugins + .build() + .disable::() .set(WindowPlugin { window: WindowDescriptor { title: "RMF Site Editor".to_owned(), @@ -155,10 +161,6 @@ pub fn run(command_line_args: Vec) { }, ..default() }) - .set(LogPlugin { - filter: "bevy_asset=error,wgpu=error".to_string(), - ..default() - }) .add_after::(SiteAssetIoPlugin), ); } @@ -166,6 +168,7 @@ pub fn run(command_line_args: Vec) { app.init_resource::() .add_startup_system(init_settings) .insert_resource(DirectionalLightShadowMap { size: 2048 }) + .add_plugin(LogHistoryPlugin) .add_plugin(AabbUpdatePlugin) .add_plugin(EguiPlugin) .add_plugin(KeyboardInputPlugin) diff --git a/rmf_site_editor/src/log.rs b/rmf_site_editor/src/log.rs new file mode 100644 index 00000000..492dc796 --- /dev/null +++ b/rmf_site_editor/src/log.rs @@ -0,0 +1,340 @@ +/* + * Copyright (C) 2022 Open Source Robotics Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * +*/ + +use bevy::{ecs::system::SystemParam, prelude::*}; +use bevy_utils::tracing::{field::Field, span::Record, Event, Id, Level, Subscriber}; +use crossbeam_channel::{unbounded, Receiver, SendError, Sender, TryRecvError}; +use std::collections::HashMap; +use std::fmt::{self, Debug, Write}; +use tracing_subscriber::{field::Visit, layer::Context, prelude::*, EnvFilter, Layer}; + +#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)] +pub enum LogCategory { + Status, + Warning, + Error, + Bevy, + Hint, +} + +impl fmt::Display for LogCategory { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + LogCategory::Hint => write!(f, "[HINT] "), + LogCategory::Status => write!(f, "[STATUS] "), + LogCategory::Warning => write!(f, "[WARNING] "), + LogCategory::Error => write!(f, "[ERROR] "), + LogCategory::Bevy => write!(f, "[BEVY] "), + } + } +} + +#[derive(Debug, Clone, Component, PartialEq, Eq)] +pub struct Log { + pub category: LogCategory, + pub message: String, +} + +impl Log { + pub fn hint(message: String) -> Log { + Log { + category: LogCategory::Hint, + message, + } + } + + pub fn status(message: String) -> Log { + Log { + category: LogCategory::Status, + message, + } + } + + pub fn warn(message: String) -> Log { + Log { + category: LogCategory::Warning, + message, + } + } + + pub fn error(message: String) -> Log { + Log { + category: LogCategory::Error, + message, + } + } +} + +pub struct LogHistoryElement { + pub log: Log, + pub copies: usize, +} + +impl From for LogHistoryElement { + fn from(value: Log) -> Self { + LogHistoryElement { + log: value, + copies: 1, + } + } +} + +impl fmt::Display for LogHistoryElement { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if self.copies > 1 { + write!( + f, + "({}x) {}{}", + self.copies, self.log.category, self.log.message + ) + } else { + write!(f, "{}{}", self.log.category, self.log.message) + } + } +} + +#[derive(Resource)] +pub struct LogHistory { + log_history: Vec, + category_filter: HashMap, + display_limit: usize, + receiver: Receiver, +} + +impl Default for LogHistory { + fn default() -> Self { + let mut filter_hashmap = HashMap::new(); + filter_hashmap.insert(LogCategory::Status, true); + filter_hashmap.insert(LogCategory::Warning, true); + filter_hashmap.insert(LogCategory::Error, true); + filter_hashmap.insert(LogCategory::Bevy, false); + filter_hashmap.insert(LogCategory::Hint, true); + + let (tx, rx) = unbounded(); + let tx_2 = tx.clone(); + let rx_2 = rx.clone(); + + let level_name = Level::INFO; + let filter_name = "bevy_asset=error,wgpu=error".to_string(); + let default_filter = { format!("{},{}", level_name, filter_name) }; + let filter_layer = EnvFilter::try_from_default_env() + .or_else(|_| EnvFilter::try_new(&default_filter)) + .unwrap(); + + let subscriber = tracing_subscriber::registry().with(LogSubscriber { sender: tx_2 }); + let subscriber = subscriber.with(filter_layer); + #[cfg(not(target_arch = "wasm32"))] + { + let fmt_layer = tracing_subscriber::fmt::Layer::default(); + let subscriber = subscriber.with(fmt_layer); + tracing::subscriber::set_global_default(subscriber); + } + #[cfg(target_arch = "wasm32")] + { + tracing::subscriber::set_global_default(subscriber); + } + + Self { + log_history: Vec::new(), + category_filter: filter_hashmap, + display_limit: 100, + receiver: rx_2, + } + } +} + +impl LogHistory { + pub fn copy_log_history(&self) -> String { + let mut output_string = String::new(); + + for element in &self.log_history { + if *self.category_filter.get(&element.log.category).unwrap() { + output_string.push_str(&element.to_string()); + output_string.push_str("\n"); + } + } + output_string + } + + pub fn log_history(&self) -> &Vec { + &self.log_history + } + + pub fn iter(&self) -> impl Iterator { + self.log_history + .iter() + .rev() + .filter(|e| self.category_filter[&e.log.category]) + .take(self.display_limit) + } + + pub fn category_present(&self, category: &LogCategory) -> &bool { + self.category_filter.get(category).unwrap() + } + + pub fn category_present_mut(&mut self, category: LogCategory) -> &mut bool { + self.category_filter.get_mut(&category).unwrap() + } + + pub fn display_limit(&self) -> usize { + self.display_limit + } + + pub fn display_limit_mut(&mut self) -> &mut usize { + &mut self.display_limit + } + + pub fn receive_logs(&mut self) { + for msg in self.receiver.try_iter().collect::>() { + self.push(msg); + } + } + + pub fn push(&mut self, log: Log) { + if let Some(last) = self.log_history.last_mut() { + if last.log == log { + last.copies += 1; + } else { + self.log_history.push(log.into()); + } + } else { + self.log_history.push(log.into()); + } + } + + pub fn top(&self) -> Option<&LogHistoryElement> { + for element in self.log_history.iter().rev() { + if self.category_filter[&element.log.category] { + return Some(element); + } + } + + None + } + + pub fn all_categories_are_selected(&self) -> bool { + for selected in self.category_filter.values() { + if !selected { + return false; + } + } + + return true; + } + + pub fn select_all_categories(&mut self) { + for selected in self.category_filter.values_mut() { + *selected = true; + } + } +} + +struct LogRecorder(String, bool); +impl LogRecorder { + fn new() -> Self { + LogRecorder(String::new(), false) + } +} + +impl Visit for LogRecorder { + fn record_debug(&mut self, field: &Field, value: &dyn Debug) { + if field.name() == "message" { + if !self.0.is_empty() { + self.0 = format!("{:?}\n{}", value, self.0) + } else { + self.0 = format!("{:?}", value) + } + } else { + if self.1 { + // following args + write!(self.0, " ").unwrap(); + } else { + // first arg + self.1 = true; + } + write!(self.0, "{} = {:?};", field.name(), value).unwrap(); + } + } +} + +impl fmt::Display for LogRecorder { + fn fmt(&self, mut f: &mut fmt::Formatter<'_>) -> fmt::Result { + if !self.0.is_empty() { + write!(&mut f, " {}", self.0) + } else { + Ok(()) + } + } +} + +pub struct LogSubscriber { + sender: Sender, +} + +impl Layer for LogSubscriber +where + S: tracing::Subscriber, +{ + fn on_event( + &self, + event: &tracing::Event<'_>, + _ctx: tracing_subscriber::layer::Context<'_, S>, + ) { + let mut recorder = LogRecorder::new(); + event.record(&mut recorder); + + // Default category + let mut category = LogCategory::Status; + let message = format!("{}", recorder); + + // Check if this is a Bevy or RMF Site log + if event.metadata().target().contains("bevy") { + category = LogCategory::Bevy; + } else { + category = match *event.metadata().level() { + Level::INFO => LogCategory::Status, + Level::WARN => LogCategory::Warning, + Level::ERROR => LogCategory::Error, + _ => LogCategory::Error, + }; + } + + let log = Log { category, message }; + let send_message = self.sender.send(log); + match send_message { + Ok(()) => send_message.unwrap(), + Err(SendError(e)) => println!("Unable to send log: {:?}", e), + } + } +} + +fn receive_logs(mut log_history: ResMut, mut log_events: EventReader) { + log_history.receive_logs(); + for log in log_events.iter() { + log_history.push(log.clone()); + } +} + +pub struct LogHistoryPlugin; + +impl Plugin for LogHistoryPlugin { + fn build(&self, app: &mut App) { + app.add_event::() + .init_resource::() + .add_system(receive_logs); + } +} diff --git a/rmf_site_editor/src/main_menu.rs b/rmf_site_editor/src/main_menu.rs index a3712a70..798466be 100644 --- a/rmf_site_editor/src/main_menu.rs +++ b/rmf_site_editor/src/main_menu.rs @@ -87,7 +87,7 @@ fn egui_ui( // TODO(@mxgrey): Bring this back when we have time to fix the // warehouse generator. // if ui.button("Warehouse generator").clicked() { - // println!("Entering warehouse generator"); + // info!("Entering warehouse generator"); // _app_state.set(AppState::WarehouseGenerator).unwrap(); // } }); diff --git a/rmf_site_editor/src/occupancy.rs b/rmf_site_editor/src/occupancy.rs index ddd44adf..1af75c53 100644 --- a/rmf_site_editor/src/occupancy.rs +++ b/rmf_site_editor/src/occupancy.rs @@ -176,7 +176,7 @@ fn calculate_grid( let levels_of_sites = get_levels_of_sites(&levels, &parents); let physical_entities = collect_physical_entities(&bodies, &meta); - println!("Checking {:?} physical entities", physical_entities.len()); + info!("Checking {:?} physical entities", physical_entities.len()); for e in &physical_entities { let (_, mesh, aabb, tf) = match bodies.get(*e) { Ok(body) => body, @@ -210,7 +210,7 @@ fn calculate_grid( let indices = match mesh.indices() { Some(Indices::U32(indices)) => indices, _ => { - println!( + warn!( "Unexpected index set for mesh of {e:?}:\n{:?}", mesh.indices() ); @@ -243,7 +243,7 @@ fn calculate_grid( let finish_time = Instant::now(); let delta = finish_time - start_time; - println!("Occupancy calculation time: {}", delta.as_secs_f32()); + info!("Occupancy calculation time: {}", delta.as_secs_f32()); for grid in &grids { commands.entity(grid).despawn_recursive(); diff --git a/rmf_site_editor/src/save.rs b/rmf_site_editor/src/save.rs index a865d3c0..2e1dde14 100644 --- a/rmf_site_editor/src/save.rs +++ b/rmf_site_editor/src/save.rs @@ -134,7 +134,7 @@ pub fn dispatch_save_events( AppState::MainMenu => { /* Noop */ } } } else { - println!("Unable to save, no workspace loaded"); + warn!("Unable to save, no workspace loaded"); return; } } diff --git a/rmf_site_editor/src/site/change_plugin.rs b/rmf_site_editor/src/site/change_plugin.rs index d6262f4e..b6924e1e 100644 --- a/rmf_site_editor/src/site/change_plugin.rs +++ b/rmf_site_editor/src/site/change_plugin.rs @@ -90,8 +90,8 @@ fn update_changed_values( .entity(change.for_element) .insert(change.to_value.clone()); } else { - println!( - "DEV ERROR: Unable to change {} data to {:?} for entity {:?} \ + error!( + "Unable to change {} data to {:?} for entity {:?} \ because the entity does not have that type", std::any::type_name::(), change.to_value, diff --git a/rmf_site_editor/src/site/deletion.rs b/rmf_site_editor/src/site/deletion.rs index ea43f410..a0305e33 100644 --- a/rmf_site_editor/src/site/deletion.rs +++ b/rmf_site_editor/src/site/deletion.rs @@ -17,6 +17,7 @@ use crate::{ interaction::{Select, Selection}, + log::Log, site::{Category, CurrentLevel, Dependents, LevelProperties, SiteUpdateStage}, }; use bevy::{ecs::system::SystemParam, prelude::*}; @@ -86,6 +87,7 @@ struct DeletionParams<'w, 's> { current_level: ResMut<'w, CurrentLevel>, levels: Query<'w, 's, Entity, With>, select: EventWriter<'w, 's, Select>, + log: EventWriter<'w, 's, Log>, } pub struct DeletionPlugin; @@ -128,16 +130,16 @@ fn cautious_delete(element: Entity, params: &mut DeletionParams) { for descendent in &all_descendents { if let Ok(prevent) = params.preventions.get(*descendent) { if *descendent == element { - println!( + params.log.send(Log::hint(format!( "Element {:?} cannot be deleted because: {}", element, prevent .reason .as_ref() .unwrap_or(&"<.. no reason given>".to_string()), - ); + ))); } else { - println!( + params.log.send(Log::hint(format!( "Element {:?} is an ancestor of {:?} which cannot be \ deleted because: {}", element, @@ -146,7 +148,7 @@ fn cautious_delete(element: Entity, params: &mut DeletionParams) { .reason .as_ref() .unwrap_or(&"<.. no reason given>".to_string()), - ); + ))); } return; } @@ -155,20 +157,20 @@ fn cautious_delete(element: Entity, params: &mut DeletionParams) { for dep in dependents.iter() { if !all_descendents.contains(dep) { if *descendent == element { - println!( + params.log.send(Log::hint(format!( "Cannot delete {:?} because it has {} dependents. \ Only elements with no outside dependents can be \ deleted.", element, dependents.len(), - ); + ))); } else { - println!( + params.log.send(Log::hint(format!( "Element {:?} is an ancestor of {:?} \ which cannot be deleted because {:?} depends \ on it.", element, descendent, dep, - ); + ))); } return; } @@ -238,16 +240,16 @@ fn recursive_dependent_delete(element: Entity, params: &mut DeletionParams) { while let Some(top) = queue.pop() { if let Ok(prevent) = params.preventions.get(top) { if top == element { - println!( + params.log.send(Log::hint(format!( "Cannot delete {:?} because: {}", element, prevent .reason .as_ref() .unwrap_or(&"<.. no reason given>".to_string()), - ); + ))); } else { - println!( + params.log.send(Log::hint(format!( "Cannot delete {:?} because we would need to also delete \ {:?} which cannot be deleted because: {}", element, @@ -256,7 +258,7 @@ fn recursive_dependent_delete(element: Entity, params: &mut DeletionParams) { .reason .as_ref() .unwrap_or(&"<.. no reason given>".to_string()), - ) + ))); } return; } diff --git a/rmf_site_editor/src/site/drawing.rs b/rmf_site_editor/src/site/drawing.rs index 7206a29e..4ff52209 100644 --- a/rmf_site_editor/src/site/drawing.rs +++ b/rmf_site_editor/src/site/drawing.rs @@ -112,7 +112,7 @@ pub fn handle_loaded_drawing( if let Ok(mut mesh_handle) = mesh_handles.get_mut(segment.leaf) { *mesh_handle = mesh; } else { - println!("DEV ERROR: Partially-constructed Drawing entity detected"); + error!("Partially-constructed Drawing entity detected"); } // We can ignore the layer height here since that update // will be handled by another system. diff --git a/rmf_site_editor/src/site/floor.rs b/rmf_site_editor/src/site/floor.rs index 9778504a..0981e8e2 100644 --- a/rmf_site_editor/src/site/floor.rs +++ b/rmf_site_editor/src/site/floor.rs @@ -165,7 +165,7 @@ fn make_floor_mesh(entity: Entity, anchor_path: &Path, anchors: &AnchorP if let Ok(p) = anchors.point_in_parent_frame_of(*anchor, Category::Floor, entity) { positions.push(p); } else { - println!("DEV ERROR: Failed to find anchor {anchor:?} used by a path"); + error!("Failed to find anchor {anchor:?} used by a path"); valid = false; } } @@ -187,7 +187,7 @@ fn make_floor_mesh(entity: Entity, anchor_path: &Path, anchors: &AnchorP let p = match anchors.point_in_parent_frame_of(*anchor, Category::Floor, entity) { Ok(a) => a, Err(_) => { - println!("DEV ERROR: Failed to find anchor {anchor:?} used by a path"); + error!("Failed to find anchor {anchor:?} used by a path"); valid = false; continue; } @@ -222,7 +222,7 @@ fn make_floor_mesh(entity: Entity, anchor_path: &Path, anchors: &AnchorP match result { Err(err) => { - println!("Failed to render floor: {err}"); + error!("Failed to render floor: {err}"); return make_fallback_floor_mesh_near_path(entity, anchor_path, anchors); } _ => {} diff --git a/rmf_site_editor/src/site/level.rs b/rmf_site_editor/src/site/level.rs index 10db811e..f7368d3b 100644 --- a/rmf_site_editor/src/site/level.rs +++ b/rmf_site_editor/src/site/level.rs @@ -41,7 +41,7 @@ pub fn assign_orphan_levels_to_site( commands.entity(site).add_child(level); } } else { - println!( + warn!( "Unable to assign level to any site because there is no \ current site" ); diff --git a/rmf_site_editor/src/site/lift.rs b/rmf_site_editor/src/site/lift.rs index 0aeeaa60..6fd2d822 100644 --- a/rmf_site_editor/src/site/lift.rs +++ b/rmf_site_editor/src/site/lift.rs @@ -127,7 +127,7 @@ pub fn add_tags_to_lift( if let Some(current_site) = current_workspace.to_site(&open_sites) { commands.entity(current_site).add_child(e); } else { - println!("Could not find a current site to put a newly created lift inside of!"); + error!("Could not find a current site to put a newly created lift inside of!"); } } @@ -363,8 +363,8 @@ pub fn update_lift_door_availability( if !all_levels.contains(toggle.on_level) { // If we're being asked to toggle availability on for something // that isn't a level, then ignore this request. - println!( - "DEV ERROR: Asking to turn on lift {:?} door {:?} availability \ + error!( + "Asking to turn on lift {:?} door {:?} availability \ for a level {:?} that does not exist.", toggle.for_lift, toggle.cabin_door, toggle.on_level, ); @@ -531,8 +531,8 @@ pub fn update_lift_door_availability( let e_lift = match parents.get(e_door) { Ok(e_lift) => e_lift, Err(_) => { - println!( - "DEV ERROR: Unable to find parent for lift door \ + error!( + "Unable to find parent for lift door \ {e_door:?} while handling a removed level" ); continue; @@ -541,7 +541,7 @@ pub fn update_lift_door_availability( let (mut cabin, _, _) = match lifts.get_mut(e_lift.get()) { Ok(cabin) => cabin, Err(_) => { - println!("DEV ERROR: Unable to find cabin for lift {e_lift:?}"); + error!("Unable to find cabin for lift {e_lift:?}"); continue; } }; diff --git a/rmf_site_editor/src/site/light.rs b/rmf_site_editor/src/site/light.rs index a14eb224..0641d338 100644 --- a/rmf_site_editor/src/site/light.rs +++ b/rmf_site_editor/src/site/light.rs @@ -67,7 +67,7 @@ pub fn add_physical_lights( if let Some(current_level) = **current_level { commands.entity(current_level).add_child(e); } else { - println!("DEV ERROR: No current level to assign light {e:?}"); + error!("No current level to assign light {e:?}"); } } } @@ -162,7 +162,7 @@ pub fn export_lights( let out_file = match std::fs::File::create(export.0.clone()) { Ok(out_file) => out_file, Err(err) => { - println!( + error!( "Failed to create file {:?} for exporting lights: {}", export.0, err, ); @@ -178,7 +178,7 @@ pub fn export_lights( } if let Err(err) = serde_yaml::to_writer(out_file, &root) { - println!("Error while exporting lights: {err}"); + error!("Error while exporting lights: {err}"); } } } diff --git a/rmf_site_editor/src/site/load.rs b/rmf_site_editor/src/site/load.rs index 8c50fdc8..c7544d52 100644 --- a/rmf_site_editor/src/site/load.rs +++ b/rmf_site_editor/src/site/load.rs @@ -235,7 +235,7 @@ fn generate_site_entities(commands: &mut Commands, site_data: &rmf_site_format:: ) { Ok(r) => r, Err(id) => { - println!( + error!( "ERROR: Nav Graph ranking could not load because a graph with \ id {id} does not exist." ); @@ -511,7 +511,7 @@ pub fn import_nav_graph( ) { for r in import_requests.iter() { if let Err(err) = generate_imported_nav_graphs(&mut params, r.into_site, &r.from_site) { - println!("Failed to import nav graph: {err}"); + error!("Failed to import nav graph: {err}"); } } @@ -571,7 +571,7 @@ pub fn import_nav_graph( if let Err(err) = generate_imported_nav_graphs(&mut params, into_site, &from_site_data) { - println!("Failed to auto-import nav graph: {err}"); + error!("Failed to auto-import nav graph: {err}"); } } } @@ -587,12 +587,12 @@ async fn load_site_file(file: &FileHandle) -> Option { Ok(building) => match building.to_site() { Ok(site) => Some(site), Err(err) => { - println!("{:?}", err); + error!("{:?}", err); return None; } }, Err(err) => { - println!("{:?}", err); + error!("{:?}", err); return None; } } @@ -600,7 +600,7 @@ async fn load_site_file(file: &FileHandle) -> Option { match Site::from_bytes(&data) { Ok(site) => Some(site), Err(err) => { - println!("{:?}", err); + error!("{:?}", err); return None; } } diff --git a/rmf_site_editor/src/site/model.rs b/rmf_site_editor/src/site/model.rs index e7d6aa25..344fe5f0 100644 --- a/rmf_site_editor/src/site/model.rs +++ b/rmf_site_editor/src/site/model.rs @@ -284,10 +284,7 @@ pub fn update_model_tentative_formats( *tentative_format = fmt; commands.entity(e).remove::(); } else { - println!( - "WARNING: Model with source {} not found", - String::from(source) - ); + warn!("Model with source {} not found", String::from(source)); commands.entity(e).remove::(); } } @@ -343,7 +340,7 @@ pub fn make_models_selectable( if let Ok(mesh_handle) = mesh_handles.get(e) { if let Some(mesh) = mesh_assets.get_mut(mesh_handle) { if mesh.generate_outline_normals().is_err() { - println!( + warn!( "WARNING: Unable to generate outline normals for \ a model mesh" ); diff --git a/rmf_site_editor/src/site/save.rs b/rmf_site_editor/src/site/save.rs index 42972aa7..3c047809 100644 --- a/rmf_site_editor/src/site/save.rs +++ b/rmf_site_editor/src/site/save.rs @@ -908,14 +908,14 @@ pub fn save_site(world: &mut World) { let save_events: Vec<_> = world.resource_mut::>().drain().collect(); for save_event in save_events { let path = save_event.to_file; - println!( + info!( "Saving to {}", path.to_str().unwrap_or("") ); let f = match std::fs::File::create(path) { Ok(f) => f, Err(err) => { - println!("Unable to save file: {err}"); + error!("Unable to save file: {err}"); continue; } }; @@ -923,17 +923,17 @@ pub fn save_site(world: &mut World) { let site = match generate_site(world, save_event.site) { Ok(site) => site, Err(err) => { - println!("Unable to compile site: {err}"); + error!("Unable to compile site: {err}"); continue; } }; match site.to_writer(f) { Ok(()) => { - println!("Save successful"); + info!("Save successful"); } Err(err) => { - println!("Save failed: {err}"); + error!("Save failed: {err}"); } } } @@ -950,7 +950,7 @@ pub fn save_nav_graphs(world: &mut World) { let mut site = match generate_site(world, save_event.site) { Ok(site) => site, Err(err) => { - println!("Unable to compile site: {err}"); + error!("Unable to compile site: {err}"); continue; } }; @@ -958,19 +958,19 @@ pub fn save_nav_graphs(world: &mut World) { for (name, nav_graph) in legacy::nav_graph::NavGraph::from_site(&site) { let mut graph_file = path.clone(); graph_file.set_file_name(name + ".nav.yaml"); - println!( + info!( "Saving legacy nav graph to {}", graph_file.to_str().unwrap_or("") ); let f = match std::fs::File::create(graph_file) { Ok(f) => f, Err(err) => { - println!("Unable to save nav graph: {err}"); + error!("Unable to save nav graph: {err}"); continue; } }; if let Err(err) = serde_yaml::to_writer(f, &nav_graph) { - println!("Failed to save nav graph: {err}"); + error!("Failed to save nav graph: {err}"); } } @@ -986,24 +986,24 @@ pub fn save_nav_graphs(world: &mut World) { level.walls.clear(); } - println!( + info!( "Saving all site nav graphs to {}", path.to_str().unwrap_or("") ); let f = match std::fs::File::create(path) { Ok(f) => f, Err(err) => { - println!("Unable to save file: {err}"); + error!("Unable to save file: {err}"); continue; } }; match site.to_writer(f) { Ok(()) => { - println!("Save successful"); + info!("Save successful"); } Err(err) => { - println!("Save failed: {err}"); + error!("Save failed: {err}"); } } } diff --git a/rmf_site_editor/src/site/sdf.rs b/rmf_site_editor/src/site/sdf.rs index 7b585bfc..9c579b81 100644 --- a/rmf_site_editor/src/site/sdf.rs +++ b/rmf_site_editor/src/site/sdf.rs @@ -145,7 +145,7 @@ pub fn handle_new_sdf_roots(mut commands: Commands, new_sdfs: Query<(Entity, &Sd Some(id) => { commands.entity(link_id).add_child(id); } - None => println!("Found unhandled geometry type {:?}", &visual.geometry), + None => warn!("Found unhandled geometry type {:?}", &visual.geometry), } } // TODO(luca) parse and display collisions diff --git a/rmf_site_editor/src/site/site.rs b/rmf_site_editor/src/site/site.rs index 00c28a29..a9c521d8 100644 --- a/rmf_site_editor/src/site/site.rs +++ b/rmf_site_editor/src/site/site.rs @@ -62,7 +62,7 @@ pub fn change_site( if let Some(cmd) = change_current_site.iter().last() { if open_sites.get(cmd.site).is_err() { - println!( + warn!( "Requested workspace change to an entity that is not an open site: {:?}", cmd.site ); @@ -76,7 +76,7 @@ pub fn change_site( .filter(|parent| parent.get() == cmd.site) .is_none() { - println!( + warn!( "Requested level change to an entity {:?} that is not a level of the requested site {:?}", chosen_level, cmd.site, diff --git a/rmf_site_editor/src/widgets/console.rs b/rmf_site_editor/src/widgets/console.rs new file mode 100644 index 00000000..2bdfa881 --- /dev/null +++ b/rmf_site_editor/src/widgets/console.rs @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2023 Open Source Robotics Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * +*/ + +use crate::{log::*, site::*, widgets::AppEvents}; +use bevy::{ecs::system::SystemParam, prelude::*}; +use bevy_egui::{ + egui::{self, CollapsingHeader, Color32, FontId, RichText, Ui}, + EguiContext, +}; + +pub struct ConsoleWidget<'a, 'w2, 's2> { + events: &'a mut AppEvents<'w2, 's2>, +} + +impl<'a, 'w2, 's2> ConsoleWidget<'a, 'w2, 's2> { + pub fn new(events: &'a mut AppEvents<'w2, 's2>) -> Self { + Self { events } + } + + pub fn show(self, ui: &mut Ui) { + ui.horizontal_wrapped(|ui| { + ui.spacing_mut().item_spacing.x = 0.5; + let status = self.events.display.log_history.top(); + match status { + Some(log) => print_log(ui, log), + None => (), + } + }); + ui.add_space(5.0); + CollapsingHeader::new("RMF Site Editor Console") + .default_open(false) + .show(ui, |ui| { + ui.horizontal_wrapped(|ui| { + ui.spacing_mut().item_spacing.x = 10.0; + // Filter logs by category + let mut all_are_checked = self + .events + .display + .log_history + .all_categories_are_selected(); + let all_were_checked = all_are_checked; + ui.checkbox(&mut all_are_checked, "All"); + ui.checkbox( + self.events + .display + .log_history + .category_present_mut(LogCategory::Status), + "Status", + ); + ui.checkbox( + self.events + .display + .log_history + .category_present_mut(LogCategory::Warning), + "Warning", + ); + ui.checkbox( + self.events + .display + .log_history + .category_present_mut(LogCategory::Error), + "Error", + ); + ui.checkbox( + self.events + .display + .log_history + .category_present_mut(LogCategory::Bevy), + "Bevy", + ); + // Copy full log history to clipboard + if ui.button("Copy Log History").clicked() { + ui.output().copied_text = + self.events.display.log_history.copy_log_history(); + }; + // Slider to adjust display limit + // TODO(@mxgrey): Consider allowing this range to + // automatically grow/shrink when the selected value + // approaches or leaves the upper limit. + ui.add(egui::Slider::new( + self.events.display.log_history.display_limit_mut(), + 10..=1000, + )); + + if !all_were_checked && all_are_checked { + // The user has asked to select all categories + self.events.display.log_history.select_all_categories(); + } + }); + ui.add_space(10.); + + egui::ScrollArea::both() + .auto_shrink([false, false]) + .stick_to_bottom(true) + .show(ui, |ui| { + let mut count = 0; + for element in self.events.display.log_history.iter() { + print_log(ui, element); + count += 1; + } + if count >= self.events.display.log_history.display_limit() { + ui.add_space(5.0); + if ui.button("See more").clicked() { + *self.events.display.log_history.display_limit_mut() += 100; + } + } + }); + ui.add_space(10.); + }); + } +} + +fn print_log(ui: &mut egui::Ui, element: &LogHistoryElement) { + ui.horizontal_wrapped(|ui| { + ui.spacing_mut().item_spacing.x = 0.5; + + if element.copies > 1 { + ui.label(RichText::new(format!("({}x) ", element.copies)).color(Color32::GOLD)); + } + // Match LogCategory to color + let category_text_color = match element.log.category { + LogCategory::Hint => Color32::LIGHT_GREEN, + LogCategory::Status => Color32::WHITE, + LogCategory::Warning => Color32::YELLOW, + LogCategory::Error => Color32::RED, + LogCategory::Bevy => Color32::LIGHT_BLUE, + }; + ui.label(RichText::new(element.log.category.to_string()).color(category_text_color)); + // Selecting the label allows users to copy log entry to clipboard + if ui + .selectable_label(false, element.log.message.to_string()) + .clicked() + { + ui.output().copied_text = element.log.category.to_string() + &element.log.message; + } + }); +} diff --git a/rmf_site_editor/src/widgets/mod.rs b/rmf_site_editor/src/widgets/mod.rs index 25a1133f..3fef1efc 100644 --- a/rmf_site_editor/src/widgets/mod.rs +++ b/rmf_site_editor/src/widgets/mod.rs @@ -19,6 +19,7 @@ use crate::{ interaction::{ ChangeMode, HeadlightToggle, Hover, MoveTo, PickingBlockers, Select, SpawnPreview, }, + log::LogHistory, occupancy::CalculateGrid, recency::ChangeRank, site::{ @@ -53,6 +54,9 @@ use view_nav_graphs::*; pub mod view_occupancy; use view_occupancy::*; +pub mod console; +pub use console::*; + pub mod icons; pub use icons::*; @@ -136,6 +140,7 @@ pub struct PanelResources<'w, 's> { pub nav_graph: ResMut<'w, NavGraphDisplay>, pub light: ResMut<'w, LightDisplay>, pub occupancy: ResMut<'w, OccupancyDisplay>, + pub log_history: ResMut<'w, LogHistory>, _ignore: Query<'w, 's, ()>, } @@ -250,6 +255,15 @@ fn site_ui_layout( }); }); + egui::TopBottomPanel::bottom("log_console") + .resizable(true) + .min_height(30.) + .max_height(300.) + .show(egui_context.ctx_mut(), |ui| { + ui.add_space(10.0); + ConsoleWidget::new(&mut events).show(ui); + }); + egui::TopBottomPanel::top("top_panel").show(egui_context.ctx_mut(), |ui| { egui::menu::bar(ui, |ui| { ui.menu_button("File", |ui| { diff --git a/rmf_site_editor/src/widgets/view_lights.rs b/rmf_site_editor/src/widgets/view_lights.rs index 1bdb9b8c..84a87ab5 100644 --- a/rmf_site_editor/src/widgets/view_lights.rs +++ b/rmf_site_editor/src/widgets/view_lights.rs @@ -112,7 +112,7 @@ impl<'a, 'w1, 's1, 'w2, 's2> ViewLights<'a, 'w1, 's1, 'w2, 's2> { if ui.button("Export Lights As...").clicked() { match &self.events.display.light.choosing_file_for_export { Some(_) => { - println!("A file is already being chosen!"); + warn!("A file is already being chosen!"); } None => { let future = AsyncComputeTaskPool::get().spawn(async move { diff --git a/rmf_site_editor/src/widgets/view_nav_graphs.rs b/rmf_site_editor/src/widgets/view_nav_graphs.rs index 7a86f38c..09f9da94 100644 --- a/rmf_site_editor/src/widgets/view_nav_graphs.rs +++ b/rmf_site_editor/src/widgets/view_nav_graphs.rs @@ -214,7 +214,7 @@ impl<'a, 'w1, 's1, 'w2, 's2> ViewNavGraphs<'a, 'w1, 's1, 'w2, 's2> { Some(into_site) => { match &self.events.display.nav_graph.choosing_file_to_import { Some(_) => { - println!("A file is already being chosen!"); + warn!("A file is already being chosen!"); } None => { let future = AsyncComputeTaskPool::get().spawn(async move { @@ -232,7 +232,7 @@ impl<'a, 'w1, 's1, 'w2, 's2> ViewNavGraphs<'a, 'w1, 's1, 'w2, 's2> { }, )), Err(err) => { - println!("Unable to parse file:\n{err}"); + error!("Unable to parse file:\n{err}"); None } } @@ -243,7 +243,7 @@ impl<'a, 'w1, 's1, 'w2, 's2> ViewNavGraphs<'a, 'w1, 's1, 'w2, 's2> { } } None => { - println!("DEV ERROR: No current site??"); + error!("No current site??"); } } } @@ -259,14 +259,14 @@ impl<'a, 'w1, 's1, 'w2, 's2> ViewNavGraphs<'a, 'w1, 's1, 'w2, 's2> { to_file: export_file.clone(), }) } else { - println!("No current site??"); + error!("No current site??"); } } } if ui.button("Export Graphs As...").clicked() { match &self.events.display.nav_graph.choosing_file_for_export { Some(_) => { - println!("A file is already being chosen!"); + warn!("A file is already being chosen!"); } None => { let future = AsyncComputeTaskPool::get().spawn(async move { diff --git a/rmf_site_editor/src/workcell/keyboard.rs b/rmf_site_editor/src/workcell/keyboard.rs index c1e1e54d..3ddd35d0 100644 --- a/rmf_site_editor/src/workcell/keyboard.rs +++ b/rmf_site_editor/src/workcell/keyboard.rs @@ -43,14 +43,14 @@ pub fn handle_workcell_keyboard_input( if keyboard_input.any_pressed([KeyCode::LShift, KeyCode::RShift]) { if keyboard_input.just_pressed(KeyCode::V) { - println!("Toggling visuals"); + info!("Toggling visuals"); for mut v in visuals.iter_mut() { v.is_visible = !v.is_visible; } } if keyboard_input.just_pressed(KeyCode::C) { - println!("Toggling collisions"); + info!("Toggling collisions"); for mut c in collisions.iter_mut() { c.is_visible = !c.is_visible; } diff --git a/rmf_site_editor/src/workcell/load.rs b/rmf_site_editor/src/workcell/load.rs index 04557cb8..abc40a34 100644 --- a/rmf_site_editor/src/workcell/load.rs +++ b/rmf_site_editor/src/workcell/load.rs @@ -128,7 +128,7 @@ fn generate_workcell_entities( .insert(Dependents(HashSet::from_iter(children.clone()))) .push_children(&children); } else { - println!("DEV error, didn't find matching entity for id {}", parent); + error!("DEV error, didn't find matching entity for id {}", parent); continue; } } @@ -142,7 +142,7 @@ pub fn load_workcell( mut site_display_state: ResMut>, ) { for cmd in load_workcells.iter() { - println!("Loading workcell"); + info!("Loading workcell"); let root = generate_workcell_entities(&mut commands, &cmd.workcell); if let Some(path) = &cmd.default_file { commands.entity(root).insert(DefaultFile(path.clone())); diff --git a/rmf_site_editor/src/workcell/mod.rs b/rmf_site_editor/src/workcell/mod.rs index d74aced0..39a1428d 100644 --- a/rmf_site_editor/src/workcell/mod.rs +++ b/rmf_site_editor/src/workcell/mod.rs @@ -74,7 +74,6 @@ fn add_wireframe_to_meshes( for e in new_meshes.iter() { for ancestor in AncestorIter::new(&parents, e) { if let Ok(_) = models.get(ancestor) { - println!("Adding wireframe to mesh {:?}", e); commands.entity(e).insert(Wireframe); } } diff --git a/rmf_site_editor/src/workcell/save.rs b/rmf_site_editor/src/workcell/save.rs index cd54ebc7..6c545bbd 100644 --- a/rmf_site_editor/src/workcell/save.rs +++ b/rmf_site_editor/src/workcell/save.rs @@ -142,7 +142,7 @@ pub fn generate_workcell( let parent = match q_site_id.get(parent.get()) { Ok(parent) => parent.0, Err(_) => { - println!("DEV Error: Parent not found for visual {:?}", parent.get()); + error!("Parent not found for visual {:?}", parent.get()); continue; } }; @@ -155,7 +155,7 @@ pub fn generate_workcell( } else if let Some(primitive) = primitive { Geometry::Primitive(primitive.clone()) } else { - println!("DEV Error, visual without primitive or mesh"); + error!("DEV Error, visual without primitive or mesh"); continue; }; if q_visuals.get(e).is_ok() { @@ -194,7 +194,7 @@ pub fn generate_workcell( let parent = match q_site_id.get(parent.get()) { Ok(parent) => parent.0, Err(_) => { - println!("DEV Error: Parent not found for anchor {:?}", parent.get()); + error!("Parent not found for anchor {:?}", parent.get()); continue; } }; @@ -234,14 +234,14 @@ pub fn save_workcell(world: &mut World) { .collect(); for save_event in save_events { let path = save_event.to_file; - println!( + info!( "Saving to {}", path.to_str().unwrap_or("") ); let f = match std::fs::File::create(path) { Ok(f) => f, Err(err) => { - println!("Unable to save file: {err}"); + error!("Unable to save file: {err}"); continue; } }; @@ -249,7 +249,7 @@ pub fn save_workcell(world: &mut World) { let workcell = match generate_workcell(world, save_event.root) { Ok(root) => root, Err(err) => { - println!("Unable to compile workcell: {err}"); + error!("Unable to compile workcell: {err}"); continue; } }; @@ -257,14 +257,14 @@ pub fn save_workcell(world: &mut World) { match save_event.format { ExportFormat::Default => match workcell.to_writer(f) { Ok(()) => { - println!("Save successful"); + info!("Save successful"); } Err(err) => { - println!("Save failed: {err}"); + error!("Save failed: {err}"); } }, ExportFormat::Urdf => { - println!("Saving to urdf"); + info!("Saving to urdf"); } } } diff --git a/rmf_site_editor/src/workcell/urdf.rs b/rmf_site_editor/src/workcell/urdf.rs index 4fd41e4a..d0fa8445 100644 --- a/rmf_site_editor/src/workcell/urdf.rs +++ b/rmf_site_editor/src/workcell/urdf.rs @@ -44,7 +44,6 @@ pub fn handle_new_urdf_roots(mut commands: Commands, new_urdfs: Query<(Entity, & .insert(RigidBody::KinematicVelocityBased) .insert(Category::Workcell) .id(); - println!("Found link {:?} - {}", link_entity, link.name); link_name_to_entity.insert(link.name.clone(), link_entity); root_links.insert(link_entity); for visual in &link.visual { @@ -106,10 +105,6 @@ pub fn handle_new_urdf_roots(mut commands: Commands, new_urdfs: Query<(Entity, & //commands.entity(*child).insert(AnchorBundle::new(Anchor::Pose3D(Pose {trans, rot}))); commands.entity(*parent).add_child(*child); root_links.remove(child); - println!( - "Adding joint between {:?} - {} and {:?} - {}", - *parent, &joint.parent.link, *child, &joint.child.link - ); commands.entity(*child).with_children(|children| { children .spawn(SpatialBundle::VISIBLE_IDENTITY) @@ -120,7 +115,6 @@ pub fn handle_new_urdf_roots(mut commands: Commands, new_urdfs: Query<(Entity, & } } for link in root_links.iter() { - println!("Found root entity {:?}", link); commands.entity(e).add_child(*link); } commands.entity(e).remove::(); diff --git a/rmf_site_editor/src/workcell/workcell.rs b/rmf_site_editor/src/workcell/workcell.rs index 9ddbca4a..218aec07 100644 --- a/rmf_site_editor/src/workcell/workcell.rs +++ b/rmf_site_editor/src/workcell/workcell.rs @@ -35,7 +35,7 @@ pub fn change_workcell( ) { if let Some(cmd) = change_current_workcell.iter().last() { if open_workcells.get(cmd.root).is_err() { - println!( + error!( "Requested workspace change to an entity that is not an open workcell: {:?}", cmd.root ); diff --git a/rmf_site_editor/src/workspace.rs b/rmf_site_editor/src/workspace.rs index ef7ec73f..eb90b2ba 100644 --- a/rmf_site_editor/src/workspace.rs +++ b/rmf_site_editor/src/workspace.rs @@ -68,7 +68,7 @@ impl WorkspaceData { } else if filename.ends_with("workcell.json") { Some(WorkspaceData::Workcell(data)) } else { - println!("Unrecognized file type {:?}", filename); + error!("Unrecognized file type {:?}", filename); None } } @@ -135,7 +135,7 @@ pub fn dispatch_new_workspace_events( if let Some(_cmd) = new_workspace.iter().last() { match state.current() { AppState::MainMenu => { - println!("DEV ERROR: Sent generic change workspace while in main menu"); + error!("Sent generic change workspace while in main menu"); } AppState::SiteEditor => { let mut levels = BTreeMap::new(); @@ -229,7 +229,7 @@ fn handle_workspace_data( ) { match workspace_data { WorkspaceData::LegacyBuilding(data) => { - println!("Opening legacy building map file"); + info!("Opening legacy building map file"); match BuildingMap::from_bytes(&data) { Ok(building) => { match building.to_site() { @@ -244,17 +244,17 @@ fn handle_workspace_data( interaction_state.set(InteractionState::Enable).ok(); } Err(err) => { - println!("Failed converting to site {:?}", err); + error!("Failed converting to site {:?}", err); } } } Err(err) => { - println!("Failed loading legacy building {:?}", err); + error!("Failed loading legacy building {:?}", err); } } } WorkspaceData::Site(data) => { - println!("Opening site file"); + info!("Opening site file"); match Site::from_bytes(&data) { Ok(site) => { // Switch state @@ -267,12 +267,12 @@ fn handle_workspace_data( interaction_state.set(InteractionState::Enable).ok(); } Err(err) => { - println!("Failed loading site {:?}", err); + error!("Failed loading site {:?}", err); } } } WorkspaceData::Workcell(data) => { - println!("Opening workcell file"); + info!("Opening workcell file"); match Workcell::from_bytes(&data) { Ok(workcell) => { // Switch state @@ -285,7 +285,7 @@ fn handle_workspace_data( interaction_state.set(InteractionState::Enable).ok(); } Err(err) => { - println!("Failed loading workcell {:?}", err); + error!("Failed loading workcell {:?}", err); } } }