Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor optional model properties #263

Open
wants to merge 26 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
4f8f1ba
Remove MobileRobotMarker from OptionalModelProperties
xiyuoh Jan 2, 2025
2923bf6
Use Mobility struct for saving
xiyuoh Jan 2, 2025
5b35ec3
Update Tasks for saving
xiyuoh Jan 2, 2025
f65bbda
Change MobileRobotMarker to RobotMarker
xiyuoh Jan 3, 2025
e33e360
Merge branch 'main' into xiyu/optional_model_properties
xiyuoh Jan 9, 2025
4de0f3a
Add Mobility to ModelDescriptionBundle
xiyuoh Jan 9, 2025
b3111a2
Use ComponentId for ModelProperty and update Mobility
xiyuoh Jan 10, 2025
a312a10
Refactor Tasks
xiyuoh Jan 13, 2025
e332401
Interactoins with locations for GoToPlace tasks
xiyuoh Jan 14, 2025
88d0ed1
Cleanup
xiyuoh Jan 14, 2025
19a8274
Insert RobotMarker
xiyuoh Jan 14, 2025
3274b60
Remove task-based interactions and GoToPlace NameInSite
xiyuoh Jan 17, 2025
edd54cc
Combine RobotMarker and OptionalModelData into Robot
xiyuoh Jan 17, 2025
dcdf8b3
Add draft collision
xiyuoh Jan 17, 2025
3fae5da
Make the inner bundle of Parented transparent
mxgrey Jan 20, 2025
a8ff8d7
Use prerelease of ron
mxgrey Jan 20, 2025
c69b6ce
Fix style
mxgrey Jan 20, 2025
6c09af4
Set up RobotPropertyData to store property kinds and move CollisionKinds
xiyuoh Jan 21, 2025
98f3dba
Move MobilityKinds into RobotPropertyData
xiyuoh Jan 21, 2025
5652be2
Fix vec2
xiyuoh Jan 21, 2025
538ebd8
Add InspectRobotPropertyPlugin for common use
xiyuoh Jan 21, 2025
7985a80
Enable visualize circle collision
xiyuoh Jan 21, 2025
d93a4db
Move Tasks into Site and remove OptionalModelData
xiyuoh Jan 23, 2025
a173474
Merge remote-tracking branch 'origin/transparent_parented' into xiyu/…
xiyuoh Jan 23, 2025
bc769fa
Cleanup
xiyuoh Jan 23, 2025
3b1e85b
Address comments
xiyuoh Jan 28, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 0 additions & 34 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion rmf_site_editor/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ pathdiff = "*"
ehttp = { version = "0.4", features = ["native-async"] }
nalgebra = "0.32.5"
anyhow = "*"
strum = "*"

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
clap = { version = "4.0.10", features = ["color", "derive", "help", "usage", "suggestions"] }
Expand Down
45 changes: 28 additions & 17 deletions rmf_site_editor/src/interaction/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,15 @@ pub fn update_model_instance_visual_cues(
&mut Selected,
&mut Hovered,
&mut Affiliation<Entity>,
Option<Ref<Tasks<Entity>>>,
Option<Ref<Tasks>>,
),
(With<ModelMarker>, Without<Group>),
>,
mut locations: Query<(&mut Selected, &mut Hovered), (With<LocationTags>, Without<ModelMarker>)>,
mut removed_components: RemovedComponents<Tasks<Entity>>,
mut locations: Query<
(&NameInSite, &mut Selected, &mut Hovered),
(With<LocationTags>, Without<ModelMarker>),
>,
mut removed_components: RemovedComponents<Tasks>,
) {
for (instance_entity, mut instance_selected, mut instance_hovered, affiliation, tasks) in
&mut model_instances
Expand Down Expand Up @@ -72,25 +75,33 @@ pub fn update_model_instance_visual_cues(
if let Some(tasks) = tasks {
xiyuoh marked this conversation as resolved.
Show resolved Hide resolved
// When tasks for an instance have changed, reset all locations from supporting this instance
if tasks.is_changed() {
for (mut location_selected, mut location_hovered) in locations.iter_mut() {
for (_, mut location_selected, mut location_hovered) in locations.iter_mut() {
location_selected.support_selected.remove(&instance_entity);
location_hovered.support_hovering.remove(&instance_entity);
}
}

if let Some(task_location) = tasks.0.first().and_then(|t| t.location()) {
if let Ok((mut location_selected, mut location_hovered)) =
locations.get_mut(task_location.0)
// Additional interaction for default tasks
if let Some(go_to_place) = tasks
.0
.first()
.and_then(|t| serde_json::from_value::<GoToPlace>(t.config.clone()).ok())
xiyuoh marked this conversation as resolved.
Show resolved Hide resolved
{
for (location_name, mut location_selected, mut location_hovered) in
locations.iter_mut()
{
if instance_selected.cue() && !is_description_selected {
location_selected.support_selected.insert(instance_entity);
} else {
location_selected.support_selected.remove(&instance_entity);
}
if instance_hovered.cue() {
location_hovered.support_hovering.insert(instance_entity);
} else {
location_hovered.support_hovering.remove(&instance_entity);
if location_name == &go_to_place.location {
if instance_selected.cue() && !is_description_selected {
location_selected.support_selected.insert(instance_entity);
} else {
location_selected.support_selected.remove(&instance_entity);
}
if instance_hovered.cue() {
location_hovered.support_hovering.insert(instance_entity);
} else {
location_hovered.support_hovering.remove(&instance_entity);
}
break;
}
}
}
Expand All @@ -99,7 +110,7 @@ pub fn update_model_instance_visual_cues(

// When instances are removed, prevent any location from supporting them
for removed in removed_components.read() {
xiyuoh marked this conversation as resolved.
Show resolved Hide resolved
for (mut location_selected, mut location_hovered) in locations.iter_mut() {
for (_, mut location_selected, mut location_hovered) in locations.iter_mut() {
location_selected.support_selected.remove(&removed);
location_hovered.support_hovering.remove(&removed);
}
Expand Down
43 changes: 24 additions & 19 deletions rmf_site_editor/src/site/load.rs
Original file line number Diff line number Diff line change
Expand Up @@ -348,17 +348,17 @@ fn generate_site_entities(
model_description_dependents.insert(model_description_entity, HashSet::new());
model_description_to_source
.insert(model_description_entity, model_description.source.0.clone());
// Insert optional model properties
for optional_property in &model_description.optional_properties.0 {
match optional_property {
OptionalModelProperty::DifferentialDrive(diff_drive) => commands
.entity(model_description_entity)
.insert(ModelProperty(diff_drive.clone())),
OptionalModelProperty::MobileRobotMarker(robot_marker) => commands
.entity(model_description_entity)
.insert(ModelProperty(robot_marker.clone())),
_ => continue,
};
// Insert optional model data
if let serde_json::Value::Object(map) = &model_description.optional_data.0 {
for (k, v) in map.iter() {
if *k == Mobility::label() {
if let Ok(mobility) = serde_json::from_value::<Mobility>(v.clone()) {
commands
.entity(model_description_entity)
.insert(ModelProperty(mobility));
}
}
}
}
}

Expand Down Expand Up @@ -396,15 +396,20 @@ fn generate_site_entities(
model_instance.name.0,
);
}

// Insert optional model properties
for optional_property in &model_instance.optional_properties.0 {
match optional_property {
OptionalModelProperty::Tasks(tasks) => {
commands.entity(model_instance_entity).insert(tasks.clone())
// Insert optional model data
if let serde_json::Value::Object(map) = &model_instance.optional_data.0 {
for (k, v) in map.iter() {
if *k == Tasks::label() {
if let Ok(tasks) = serde_json::from_value::<Tasks>(v.clone()) {
commands.entity(model_instance_entity).insert(tasks);
if let Some(description_entity) = model_instance.description.0 {
commands
.entity(description_entity)
.insert(ModelProperty(RobotMarker));
}
}
}
_ => continue,
};
}
}
}

Expand Down
65 changes: 23 additions & 42 deletions rmf_site_editor/src/site/save.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1200,7 +1200,7 @@ fn migrate_relative_paths(
fn generate_model_descriptions(
site: Entity,
world: &mut World,
) -> Result<BTreeMap<u32, ModelDescriptionBundle<u32>>, SiteGenerationError> {
) -> Result<BTreeMap<u32, ModelDescriptionBundle>, SiteGenerationError> {
let mut state: SystemState<(
Query<
(
Expand All @@ -1213,13 +1213,14 @@ fn generate_model_descriptions(
(With<ModelMarker>, With<Group>, Without<Pending>),
>,
Query<&Children>,
// Optional model properties
Query<&ModelProperty<DifferentialDrive>>,
Query<&ModelProperty<MobileRobotMarker>>,
// Optional model data
// TODO(@xiyuoh) store property data in optional_data instead of querying
// on save or query ModelProperty<T> instead but exclude required
Query<&ModelProperty<Mobility>>,
)> = SystemState::new(world);
let (model_descriptions, children, differential_drive, robot_marker) = state.get(world);
let (model_descriptions, children, mobility) = state.get(world);

let mut res = BTreeMap::<u32, ModelDescriptionBundle<u32>>::new();
let mut res = BTreeMap::<u32, ModelDescriptionBundle>::new();
if let Ok(children) = children.get(site) {
for child in children.iter() {
if let Ok((site_id, name, source, is_static, scale)) = model_descriptions.get(*child) {
Expand All @@ -1230,16 +1231,14 @@ fn generate_model_descriptions(
scale: scale.clone(),
..Default::default()
};
if let Ok(diff_drive) = differential_drive.get(*child) {
desc_bundle.optional_properties.0.push(
OptionalModelProperty::DifferentialDrive(diff_drive.0.clone()),
);
};
if let Ok(mobile_robot) = robot_marker.get(*child) {
desc_bundle.optional_properties.0.push(
OptionalModelProperty::MobileRobotMarker(mobile_robot.0.clone()),
);
};
let mut optional_data = serde_json::Map::new();
if let Ok(mobility_property) = mobility.get(*child) {
if let Ok(mobility_data) = serde_json::to_value(mobility_property.0.clone()) {
optional_data.insert(Mobility::label(), mobility_data.into());
}
}
desc_bundle.optional_data = OptionalModelData(optional_data.into());

res.insert(site_id.0, desc_bundle);
}
}
Expand All @@ -1258,13 +1257,11 @@ fn generate_model_instances(
(With<ModelMarker>, Without<Group>, Without<Pending>),
>,
Query<(Entity, &SiteID), With<LevelElevation>>,
Query<(&Point<Entity>, &SiteID), (With<LocationTags>, Without<Pending>)>,
Query<&Children>,
Query<&Parent>,
Query<&Tasks<Entity>, (With<MobileRobotMarker>, Without<Group>)>,
Query<&Tasks, (With<RobotMarker>, Without<Group>)>,
)> = SystemState::new(world);
let (model_descriptions, model_instances, levels, locations, _, parents, tasks) =
state.get(world);
let (model_descriptions, model_instances, levels, _, parents, tasks) = state.get(world);

let mut site_levels_ids = std::collections::HashMap::<Entity, u32>::new();
for (level_entity, site_id) in levels.iter() {
Expand Down Expand Up @@ -1296,30 +1293,14 @@ fn generate_model_instances(
),
..Default::default()
};
let mut optional_data = serde_json::Map::new();
if let Ok(robot_tasks) = tasks.get(instance_entity) {
let tasks: Vec<Task<u32>> = robot_tasks
.0
.clone()
.iter()
.map(|task| match task {
Task::GoToPlace(go_to_place) => locations
.get(go_to_place.location.unwrap().0)
.map(|(_, location_id)| {
Task::GoToPlace(GoToPlace {
location: Some(Point(location_id.0)),
})
})
.unwrap(),
Task::WaitFor(wait_for) => Task::WaitFor(WaitFor {
duration: wait_for.duration.clone(),
}),
})
.collect::<Vec<Task<u32>>>();
model_instance
.optional_properties
.0
.push(OptionalModelProperty::Tasks(Tasks(tasks.clone())));
if let Ok(tasks_data) = serde_json::to_value(robot_tasks.clone()) {
optional_data.insert("Tasks".to_string(), tasks_data.into());
}
}
model_instance.optional_data = OptionalModelData(optional_data.into());

res.insert(
instance_id.0,
Parented {
Expand Down
17 changes: 8 additions & 9 deletions rmf_site_editor/src/widgets/creation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,15 +248,14 @@ impl<'w, 's> Creation<'w, 's> {
};
if ui.button(add_icon).clicked() {
if let Some(site_entity) = self.current_workspace.root {
let model_description_bundle: ModelDescriptionBundle<
Entity,
> = ModelDescriptionBundle {
name: NameInSite(pending_model.name.clone()),
source: ModelProperty(pending_model.source.clone()),
is_static: ModelProperty(IsStatic::default()),
scale: ModelProperty(pending_model.scale.clone()),
..Default::default()
};
let model_description_bundle: ModelDescriptionBundle =
ModelDescriptionBundle {
name: NameInSite(pending_model.name.clone()),
source: ModelProperty(pending_model.source.clone()),
is_static: ModelProperty(IsStatic::default()),
scale: ModelProperty(pending_model.scale.clone()),
..Default::default()
};
let description_entity = self
.commands
.spawn(model_description_bundle)
Expand Down
2 changes: 1 addition & 1 deletion rmf_site_editor/src/widgets/fuel_asset_browser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ impl<'w, 's> FuelAssetBrowser<'w, 's> {
if let Some(selected) = &gallery_status.selected {
if ui.button("Load as Description").clicked() {
if let Some(site_entity) = self.current_workspace.root {
let model_description: ModelDescriptionBundle<Entity> =
let model_description: ModelDescriptionBundle =
ModelDescriptionBundle {
name: NameInSite(selected.owner.clone() + "/" + &selected.name),
source: ModelProperty(AssetSource::Remote(
Expand Down
2 changes: 2 additions & 0 deletions rmf_site_editor/src/widgets/inspector/inspect_asset_source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ impl<'a> InspectAssetSourceComponent<'a> {
ui.text_edit_singleline(path);
}
}
ui.add_space(10.0);

if &new_source != self.source {
Some(new_source)
} else {
Expand Down
Loading
Loading