diff --git a/rmf_site_editor/src/site/load.rs b/rmf_site_editor/src/site/load.rs index f839eb60..cfc7c24e 100644 --- a/rmf_site_editor/src/site/load.rs +++ b/rmf_site_editor/src/site/load.rs @@ -17,10 +17,7 @@ use crate::{recency::RecencyRanking, site::*, WorkspaceMarker}; use bevy::{ecs::system::SystemParam, prelude::*}; -use std::{ - collections::{BTreeMap, HashMap}, - path::PathBuf, -}; +use std::{collections::HashMap, path::PathBuf}; use thiserror::Error as ThisError; /// This component is given to the site to keep track of what file it should be @@ -256,27 +253,12 @@ fn generate_site_entities( consider_id(*model_description_id); } - let (default_scenario_id, default_scenario) = site_data - .scenarios - .first_key_value() - .expect("No scenarios found"); - let active_model_instance_ids: std::collections::HashSet = default_scenario - .scenario - .added_model_instances - .iter() - .map(|(id, _)| *id) - .collect(); for (model_instance_id, model_instance) in &site_data.model_instances { let model_instance = model_instance.convert(&id_to_entity).for_site(site_id)?; - let model_instance_parent = if active_model_instance_ids.contains(model_instance_id) { - model_instance.parent.0.unwrap_or(site_id) - } else { - site_id - }; let model_instance_entity = commands .spawn(model_instance.clone()) .insert(SiteID(*model_instance_id)) - .set_parent(model_instance_parent) + .set_parent(site_id) .id(); id_to_entity.insert(*model_instance_id, model_instance_entity); consider_id(*model_instance_id); diff --git a/rmf_site_editor/src/site/model.rs b/rmf_site_editor/src/site/model.rs index 7cf5a59b..d3d64455 100644 --- a/rmf_site_editor/src/site/model.rs +++ b/rmf_site_editor/src/site/model.rs @@ -17,7 +17,7 @@ use crate::{ interaction::{DragPlaneBundle, Selectable, MODEL_PREVIEW_LAYER}, - site::{Category, Group, Members, PreventDeletion, SiteAssets}, + site::{Category, Group, PreventDeletion, SiteAssets}, site_asset_io::MODEL_ENVIRONMENT_VARIABLE, }; use bevy::{ @@ -31,8 +31,7 @@ use rmf_site_format::{ Affiliation, AssetSource, ModelMarker, ModelProperty, NameInSite, Pending, Pose, Scale, }; use smallvec::SmallVec; -use std::{any::TypeId, collections::HashMap}; -use yaserde::xml::name; +use std::any::TypeId; #[derive(Component, Debug, Clone)] pub struct ModelScene { @@ -490,7 +489,7 @@ pub fn propagate_model_render_layers( pub fn update_model_instances( mut commands: Commands, - mut model_properties: Query< + model_properties: Query< (Entity, &NameInSite, Ref>), (With, With), >, @@ -498,7 +497,7 @@ pub fn update_model_instances( ) { for (instance_entity, affiliation) in model_instances.iter() { if let Some(description_entity) = affiliation.0 { - if let Ok((_, name, property)) = model_properties.get(description_entity) { + if let Ok((_, _, property)) = model_properties.get(description_entity) { if property.is_changed() || affiliation.is_changed() { let mut cmd = commands.entity(instance_entity); cmd.remove::>(); @@ -508,6 +507,3 @@ pub fn update_model_instances( } } } - -#[derive(Component)] -pub struct Inactive; diff --git a/rmf_site_editor/src/site/scenario.rs b/rmf_site_editor/src/site/scenario.rs index f320dec4..015b3a23 100644 --- a/rmf_site_editor/src/site/scenario.rs +++ b/rmf_site_editor/src/site/scenario.rs @@ -15,35 +15,116 @@ * */ -use crate::site::CurrentScenario; +use crate::{site::CurrentScenario, CurrentWorkspace}; use bevy::prelude::*; -use rmf_site_format::{Group, ModelMarker, NameInSite, Pose}; +use rmf_site_format::{Group, ModelMarker, NameInSite, Pose, Scenario, SiteParent}; +use std::collections::HashMap; #[derive(Clone, Copy, Debug, Event)] pub struct ChangeCurrentScenario(pub Entity); pub fn update_current_scenario( + mut commands: Commands, mut change_current_scenario: EventReader, mut current_scenario: ResMut, - scenarios: Query, + current_workspace: Res, + scenarios: Query<&Scenario>, + mut model_instances: Query< + (Entity, &mut Pose, &SiteParent, &mut Visibility), + (With, Without), + >, ) { - for ChangeCurrentScenario(new_scenario_entity) in change_current_scenario.read() { - *current_scenario = CurrentScenario(Some(*new_scenario_entity)); - println!("Changed scenario"); + for ChangeCurrentScenario(scenario_entity) in change_current_scenario.read() { + // Used to build a scenario from root + let mut scenario_stack = Vec::<&Scenario>::new(); + let mut scenario = scenarios + .get(*scenario_entity) + .expect("Failed to get scenario entity"); + loop { + scenario_stack.push(scenario); + if let Some(scenario_parent) = scenario.parent_scenario.0 { + scenario = scenarios + .get(scenario_parent) + .expect("Scenario parent doesn't exist"); + } else { + break; + } + } + + // Iterate stack to identify instances and poses in this model + let mut active_model_instances = HashMap::::new(); + for scenario in scenario_stack.iter().rev() { + for (e, pose) in scenario.added_model_instances.iter() { + active_model_instances.insert(*e, pose.clone()); + } + for (e, pose) in scenario.moved_model_instances.iter() { + active_model_instances.insert(*e, pose.clone()); + } + for e in scenario.removed_model_instances.iter() { + active_model_instances.remove(e); + } + } + + let current_site_entity = match current_workspace.root { + Some(current_site) => current_site, + None => return, + }; + + // If active, assign parent to level, otherwise assign parent to site + for (entity, mut pose, parent, mut visibility) in model_instances.iter_mut() { + if let Some(new_pose) = active_model_instances.get(&entity) { + commands.entity(entity).set_parent(parent.0.unwrap()); + *pose = new_pose.clone(); + *visibility = Visibility::Inherited; + } else { + commands.entity(entity).set_parent(current_site_entity); + *visibility = Visibility::Hidden; + } + } + + *current_scenario = CurrentScenario(Some(*scenario_entity)); } } pub fn update_scenario_properties( current_scenario: Res, + mut scenarios: Query<&mut Scenario>, changed_models: Query<(Entity, &NameInSite, Ref), (With, Without)>, ) { - for (e, name, pose) in changed_models.iter() { - if pose.is_added() { - println!("Added: {}", name.0); - } + if let Some(mut current_scenario) = current_scenario + .0 + .and_then(|entity| scenarios.get_mut(entity).ok()) + { + for (entity, _, pose) in changed_models.iter() { + if pose.is_changed() { + let existing_added_model = current_scenario + .added_model_instances + .iter_mut() + .find(|(e, _)| *e == entity); + if let Some(existing_added_model) = existing_added_model { + existing_added_model.1 = pose.clone(); + return; + } else if pose.is_added() { + current_scenario + .added_model_instances + .push((entity, pose.clone())); + return; + } - if !pose.is_added() && pose.is_changed() { - println!("Moved: {}", name.0) + let existing_moved_model = current_scenario + .moved_model_instances + .iter_mut() + .find(|(e, _)| *e == entity); + if let Some(existing_moved_model) = existing_moved_model { + existing_moved_model.1 = pose.clone(); + return; + } else { + current_scenario + .moved_model_instances + .push((entity, pose.clone())); + return; + } + } } } } diff --git a/rmf_site_editor/src/site/site.rs b/rmf_site_editor/src/site/site.rs index ae461b5a..56a6129d 100644 --- a/rmf_site_editor/src/site/site.rs +++ b/rmf_site_editor/src/site/site.rs @@ -17,10 +17,14 @@ use crate::{interaction::CameraControls, CurrentWorkspace}; use bevy::prelude::*; +use itertools::Itertools; use rmf_site_format::{ - LevelElevation, LevelProperties, NameInSite, NameOfSite, Pose, UserCameraPoseMarker, + LevelElevation, LevelProperties, NameInSite, NameOfSite, Pose, ScenarioBundle, ScenarioMarker, + UserCameraPoseMarker, }; +use super::ChangeCurrentScenario; + /// Used as an event to command that a new site should be made the current one #[derive(Clone, Copy, Debug, Event)] pub struct ChangeCurrentSite { @@ -50,15 +54,17 @@ pub struct NextSiteID(pub u32); pub fn change_site( mut commands: Commands, mut change_current_site: EventReader, + mut change_current_scenario: EventWriter, mut current_workspace: ResMut, mut current_level: ResMut, - mut current_scenario: ResMut, + current_scenario: ResMut, cached_levels: Query<&CachedLevel>, mut visibility: Query<&mut Visibility>, open_sites: Query>, children: Query<&Children>, parents: Query<&Parent>, levels: Query>, + scenarios: Query>, ) { let mut set_visibility = |entity, value| { if let Ok(mut v) = visibility.get_mut(entity) { @@ -139,6 +145,30 @@ pub fn change_site( } } } + + if let Some(new_scenario) = cmd.scenario { + if let Some(previous_scenario) = current_scenario.0 { + if previous_scenario != new_scenario { + change_current_scenario.send(ChangeCurrentScenario(new_scenario)); + } + } + } else { + if let Ok(children) = children.get(cmd.site) { + let any_scenario = children + .iter() + .filter(|child| scenarios.get(**child).is_ok()) + .find_or_first(|_| true); + if let Some(new_scenario) = any_scenario { + change_current_scenario.send(ChangeCurrentScenario(*new_scenario)); + } else { + let new_scenario = commands + .spawn(ScenarioBundle::::default()) + .set_parent(cmd.site) + .id(); + change_current_scenario.send(ChangeCurrentScenario(new_scenario)); + } + } + } } } diff --git a/rmf_site_editor/src/widgets/inspector/inspect_group.rs b/rmf_site_editor/src/widgets/inspector/inspect_group.rs index b7d2368f..64979d93 100644 --- a/rmf_site_editor/src/widgets/inspector/inspect_group.rs +++ b/rmf_site_editor/src/widgets/inspector/inspect_group.rs @@ -17,8 +17,8 @@ use crate::{ site::{ - Affiliation, AssetSource, Change, DefaultFile, Group, IsStatic, Members, ModelProperty, - NameInSite, Scale, Texture, + Affiliation, AssetSource, Change, DefaultFile, Group, Members, ModelProperty, NameInSite, + Texture, }, widgets::{inspector::InspectTexture, prelude::*, Inspect, SelectorWidget}, CurrentWorkspace, @@ -33,8 +33,6 @@ pub struct InspectGroup<'w, 's> { names: Query<'w, 's, &'static NameInSite>, textures: Query<'w, 's, &'static Texture>, model_assets: Query<'w, 's, &'static ModelProperty>, - is_static: Query<'w, 's, &'static ModelProperty>, - scale: Query<'w, 's, &'static ModelProperty>, members: Query<'w, 's, &'static Members>, default_file: Query<'w, 's, &'static DefaultFile>, current_workspace: Res<'w, CurrentWorkspace>, @@ -73,7 +71,7 @@ impl<'w, 's> InspectGroup<'w, 's> { .root .map(|e| self.default_file.get(e).ok()) .flatten(); - if let Ok(ModelProperty(asset)) = self.model_assets.get(id) { + if let Ok(ModelProperty(_)) = self.model_assets.get(id) { ui.label(RichText::new("Model Description Properties").size(18.0)); ui.add_space(10.0); } diff --git a/rmf_site_editor/src/widgets/view_groups.rs b/rmf_site_editor/src/widgets/view_groups.rs index f404ec08..f536d2d0 100644 --- a/rmf_site_editor/src/widgets/view_groups.rs +++ b/rmf_site_editor/src/widgets/view_groups.rs @@ -194,7 +194,7 @@ impl<'w, 's> ViewGroups<'w, 's> { }); for child in children { - let Ok((name, asset_source, site_id)) = q_groups.get(*child) else { + let Ok((name, _, site_id)) = q_groups.get(*child) else { continue; }; let text = site_id diff --git a/rmf_site_editor/src/widgets/view_scenarios.rs b/rmf_site_editor/src/widgets/view_scenarios.rs index 53ef513e..a05d6cb8 100644 --- a/rmf_site_editor/src/widgets/view_scenarios.rs +++ b/rmf_site_editor/src/widgets/view_scenarios.rs @@ -21,7 +21,7 @@ use crate::{ ScenarioMarker, }, widgets::prelude::*, - AppState, Icons, + Icons, }; use bevy::{ecs::system::SystemParam, prelude::*}; use bevy_egui::egui::{Button, CollapsingHeader, Color32, Ui}; @@ -212,7 +212,7 @@ impl<'w, 's> ViewScenarios<'w, 's> { let mut version = 1; self.scenarios .iter() - .filter(|(e, name, scenario)| scenario.parent_scenario.0.is_none()) + .filter(|(_, _, scenario)| scenario.parent_scenario.0.is_none()) .for_each(|(scenario_entity, _, _)| { show_scenario_widget( ui, @@ -244,7 +244,7 @@ fn show_scenario_widget( >, icons: &Res, ) { - let (entity, name, scenario) = q_scenario.get(scenario_entity).unwrap(); + let (entity, name, _) = q_scenario.get(scenario_entity).unwrap(); let scenario_version_str = scenario_version .iter() .map(|v| v.to_string()) @@ -257,7 +257,6 @@ fn show_scenario_widget( change_current_scenario.send(ChangeCurrentScenario(entity)); } ui.colored_label(Color32::DARK_GRAY, scenario_version_str.clone()); - ui.label(name.0.clone()); let mut new_name = name.0.clone(); if ui.text_edit_singleline(&mut new_name).changed() { change_name.send(Change::new(NameInSite(new_name), entity));